C語(yǔ)言超詳細(xì)講解排序算法下篇
上期學(xué)習(xí)完了前四個(gè)排序,這期我們來學(xué)習(xí)剩下的三個(gè)排序
1、冒泡排序
冒泡排序是我們相對(duì)最好理解的個(gè)排序,但是有些小優(yōu)化的地方我會(huì)指出來,我們先看圖解:

void BubbleSort(int* a, int n)//升序
{
//時(shí)間復(fù)雜度O(N^2)
while (n > 0)
{
int exchange = 0;
for (int i = 1; i < n; ++i)//防止越界訪問
{
if (a[i - 1] > a[i])
{
Swap(&a[i - 1], &a[i]);//交換
exchange = 1;
}
}
if (exchange == 0)
{
break;
}
--n;
}
}代碼分析:我們每排完一趟,就可以確定最后一個(gè)位置的數(shù),再者我們定義了一個(gè)exchange來判斷在排序過程中是否發(fā)生了交換,如果沒有發(fā)生交換,證明此數(shù)組已經(jīng)有序,我們可以直接跳出循環(huán),避免不必要的循環(huán)!
冒泡排序的特性總結(jié):
1. 冒泡排序是一種非常容易理解的排序
2. 時(shí)間復(fù)雜度:O(N^2) 、空間復(fù)雜度:O(1)
3. 穩(wěn)定性:穩(wěn)定
2、快速排序 ( 三種方法 )
快速排序是Hoare于1962年提出的一種二叉樹結(jié)構(gòu)的交換排序方法。
基本思想為:任取待排序元素序列中的某元素作為基準(zhǔn)值,按照該排序碼將待排序集合分割成兩子序列,左子序列中所有元素均小于基準(zhǔn)值,右子序列中所有元素均大于基準(zhǔn)值,然后最左右子序列重復(fù)該過程,直到所有元素都排列在相應(yīng)位置上為止。
第一種方法是我們最常見的挖坑法:

代碼實(shí)現(xiàn)如下:
void QuickSort(int* a, int left, int right)//升序
{
if (left >= right)
{
return;
}
int begin = left;
int end = right;
int pivot = begin;
int key = a[begin];
while (begin < end)
{
//右邊找小
while (begin < end && a[end] >= key) //這里如果不寫begin<end的話可能會(huì)出現(xiàn)越界訪問
{
--end;
}
//小的放到左邊的坑里,自己形成了新的坑位
a[pivot] = a[end];
pivot = end;
//左邊找大
while (begin < end && a[begin] <= key)
{
++begin;
}
//大的放到左邊的坑里,自己形成了新的坑位
a[pivot] = a[begin];
pivot = begin;
}
//當(dāng)begin和end相遇,證明他們兩都到了坑的位置
pivot = begin;//隨便給一個(gè)
a[pivot] = key;
//[left, pivot - 1] pivot [pivot+ 1, right]
//左子區(qū)間和右子區(qū)間有序,我們就有序了,如何讓他們有序呢?分治遞歸
QuickSort(a, left, key - 1);
QuickSort(a, key + 1, right);
}
//函數(shù)傳參:QuickSort(arr, 0, sizeof(arr) / sizeof(int) - 1);第二種方法左右指針法:

代碼實(shí)現(xiàn)如下:
void QuickSort(int* a, int left, int right)//升序
{
if (left >= right)
{
return;
}
int begin = left;
int end = right;
int keyi = begin;
while (begin < end)
{
//找小
while (begin < end && a[end] >= a[keyi])
{
--end;
}
//找大
while (begin < end && a[begin] <= a[keyi])
{
++begin;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[keyi]);
keyi = begin;
//[left, keyi - 1] keyIndex [keyi + 1, right]
//左子區(qū)間和右子區(qū)間有序,我們就有序了,如何讓他們有序呢?分治遞歸
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}第三種方法前后指針法:

代碼實(shí)現(xiàn)如下:
void QuickSort(int* a, int left, int right)//升序
{
if (left >= right)
{
return;
}
int keyi = left;
int prev = left;
int cur = left + 1;
while (cur <= right)
{
//++prev != cur為了防止自己跟自己交換造成不必要的消耗
if (a[cur] < a[keyi] && ++prev != cur)
{
Swap(&a[prev], &a[cur]);
}
++cur;
}
Swap(&a[keyi], &a[prev]);
keyi = prev;
//[left, keyi - 1] keyi [keyi + 1, right]
//左子區(qū)間和右子區(qū)間有序,我們就有序了,如何讓他們有序呢?分治遞歸
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}3、歸并排序
基本思想: 歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法 (Divide and Conquer)的一個(gè)非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個(gè)子序列有序,再使子序列段間有序。若將兩個(gè)有序表合并成一個(gè)有序表,稱為二路歸并。

歸并排序我們思想還是和快排思想差不多采用分治算法,當(dāng)數(shù)組被分為單獨(dú)一個(gè)元素就是有序的了(見上圖),在接著歸并到一個(gè)數(shù)組中,即可實(shí)現(xiàn)排序!
代碼實(shí)現(xiàn)如下:
void _MergeSort(int* a, int left, int right, int* tmp)
{
if (left >= right)
return;
int mid = (left + right) >> 1;
// 假設(shè)[left, mid] [mid + 1, right] 有序,那么我們就可以歸并了
_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid + 1, right, tmp);
//歸并
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
//拷貝回去
for (int i = left; i <= right; ++i)
{
a[i] = tmp[i];
}
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
}4、排序算法復(fù)雜度及穩(wěn)定性分析

穩(wěn)定性:假定在待排序的記錄序列中,存在多個(gè)具有相同的關(guān)鍵字的記錄,若經(jīng)過排序,這些記錄的相對(duì)次序保持不變,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍 在r[j]之前,則稱這種排序算法是穩(wěn)定的;否則稱為不穩(wěn)定的。
gitee(碼云):Mercury. (zzwlwp) - Gitee.com
到此這篇關(guān)于C語(yǔ)言超詳細(xì)講解排序算法下篇的文章就介紹到這了,更多相關(guān)C語(yǔ)言 排序算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c語(yǔ)言實(shí)現(xiàn)足球比賽積分統(tǒng)計(jì)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了c語(yǔ)言實(shí)現(xiàn)足球比賽積分統(tǒng)計(jì)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
C語(yǔ)言數(shù)組棧實(shí)現(xiàn)模板
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言數(shù)組棧實(shí)現(xiàn)模板,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
C++中靜態(tài)成員函數(shù)與靜態(tài)成員變量(static )
這篇文章主要介紹了C++中靜態(tài)成員函數(shù)與靜態(tài)成員變量(static )的相關(guān)資料,需要的朋友可以參考下2017-06-06
SublimeText編譯C開發(fā)環(huán)境設(shè)置
這篇文章主要介紹了使用SublimeText編譯C代碼的開發(fā)環(huán)境設(shè)置,大家參考使用2013-11-11

