C語言十大經(jīng)典排序算法(動態(tài)演示+代碼,值得收藏)!

§ 時間、空間復(fù)雜度比較

排序算法平均時間復(fù)雜度最差時間復(fù)雜度空間復(fù)雜度數(shù)據(jù)對象穩(wěn)定性

1、冒泡排序

算法思想

比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。

對每一對相鄰元素作同樣的工作,從開始第一對到結(jié)尾的最后一對。這步做完后,最后的元素會是最大的數(shù)。

針對所有的元素重復(fù)以上的步驟,除了最后一個。

持續(xù)每次對越來越少的元素重復(fù)上面的步驟,直到?jīng)]有任何一對數(shù)字需要比較。

冒泡排序動圖演示:

代碼:


2、選擇排序

算法思想

Ⅰ.? 在未排序序列中找到最?。ù螅┰?,存放到排序序列的起始位置

Ⅱ.? 從剩余未排序元素中繼續(xù)尋找最小(大)元素,然后放到已排序序列的末尾

Ⅲ.? 以此類推,直到所有元素均排序完畢


選擇排序動圖演示:

代碼:


3、插入排序

算法思想

從第一個元素開始,該元素可以認(rèn)為已經(jīng)被排序

取出下一個元素,在已經(jīng)排序的元素序列中從后向前掃描

如果該元素(已排序)大于新元素,將該元素移到下一位置

重復(fù)步驟3,直到找到已排序的元素小于或者等于新元素的位置

將新元素插入到該位置后

重復(fù)步驟2~5


插入排序動圖演示:

代碼:


4、快速排序

算法思想

選取第一個數(shù)為基準(zhǔn)

將比基準(zhǔn)小的數(shù)交換到前面,比基準(zhǔn)大的數(shù)交換到后面

對左右區(qū)間重復(fù)第二步,直到各區(qū)間只有一個數(shù)


快速排序動圖演示:


代碼:


5、堆排序

? ? ? ?堆排序(Heapsort)是指利用堆這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計(jì)的一種排序算法。堆積是一個近似完全二叉樹的結(jié)構(gòu),并同時滿足堆積的性質(zhì):即子結(jié)點(diǎn)的鍵值或索引總是小于(或者大于)它的父節(jié)點(diǎn)。

算法思想

將初始待排序關(guān)鍵字序列(R1,R2….Rn)構(gòu)建成大頂堆,此堆為初始的無序區(qū);

將堆頂元素R[1]與最后一個元素R[n]交換,此時得到新的無序區(qū)(R1,R2,……Rn-1)和新的有序區(qū)(Rn),且滿足R[1,2…n-1]<=R[n];

由于交換后新的堆頂R[1]可能違反堆的性質(zhì),因此需要對當(dāng)前無序區(qū)(R1,R2,……Rn-1)調(diào)整為新堆,然后再次將R[1]與無序區(qū)最后一個元素交換,得到新的無序區(qū)(R1,R2….Rn-2)和新的有序區(qū)(Rn-1,Rn)。不斷重復(fù)此過程直到有序區(qū)的元素個數(shù)為n-1,則整個排序過程完成。


代碼:

#include <iostream>

#include <algorithm>

using namespace std;

// 堆排序:(最大堆,有序區(qū))。從堆頂把根卸出來放在有序區(qū)之前,再恢復(fù)堆。

void max_heapify(int arr[], int start, int end) {

//建立父節(jié)點(diǎn)指標(biāo)和子節(jié)點(diǎn)指標(biāo)

int dad = start;

int son = dad * 2 + 1;

while (son <= end) { //若子節(jié)點(diǎn)在范圍內(nèi)才做比較

if (son + 1 <= end && arr[son] < arr[son + 1]) //先比較兩個子節(jié)點(diǎn)指標(biāo),選擇最大的

son++;

if (arr[dad] > arr[son]) //如果父節(jié)點(diǎn)大于子節(jié)點(diǎn)代表調(diào)整完成,直接跳出函數(shù)

return;

else { //否則交換父子內(nèi)容再繼續(xù)子節(jié)點(diǎn)與孫節(jié)點(diǎn)比較

swap(arr[dad], arr[son]);

dad = son;

son = dad * 2 + 1;

}

}

}

void heap_sort(int arr[], int len) {

//初始化,i從最后一個父節(jié)點(diǎn)開始調(diào)整

for (int i = len / 2 - 1; i >= 0; i--)

max_heapify(arr, i, len - 1);

//先將第一個元素和已經(jīng)排好的元素前一位做交換,再從新調(diào)整(剛調(diào)整的元素之前的元素),直到排序完成

for (int i = len - 1; i > 0; i--) {

swap(arr[0], arr[i]);

max_heapify(arr, 0, i - 1);

}

}

int main() {

int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };

int len = (int) sizeof(arr) / sizeof(*arr);

heap_sort(arr, len);

for (int i = 0; i < len; i++)

cout << arr[i] << ' ';

cout << endl;

return 0;

}


6、歸并排序

? ? ? ?歸并排序是建立在歸并操作上的一種有效的排序算法。該算法是采用分治法(Divide and Conquer)的一個非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為2-路歸并。

算法思想

1.把長度為n的輸入序列分成兩個長度為n/2的子序列;

2. 對這兩個子序列分別采用歸并排序;

3. 將兩個排序好的子序列合并成一個最終的排序序列。


歸并排序動圖演示:

代碼:


7、希爾排序

? ? ? ?希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進(jìn)版本。但希爾排序是非穩(wěn)定排序算法。先將整個待排序的記錄序列分割成為若干子序列分別進(jìn)行直接插入排序.

算法思想

選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;

按增量序列個數(shù)k,對序列進(jìn)行k 趟排序;

每趟排序,根據(jù)對應(yīng)的增量ti,將待排序列分割成若干長度為m 的子序列,分別對各子表進(jìn)行直接插入排序。僅增量因子為1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。

希爾排序動圖演示:

代碼:


8、計(jì)數(shù)排序

計(jì)數(shù)排序統(tǒng)計(jì)小于等于該元素值的元素的個數(shù)i,于是該元素就放在目標(biāo)數(shù)組的索引i位(i≥0)。

計(jì)數(shù)排序基于一個假設(shè),待排序數(shù)列的所有數(shù)均為整數(shù),且出現(xiàn)在(0,k)的區(qū)間之內(nèi)。

如果 k(待排數(shù)組的最大值) 過大則會引起較大的空間復(fù)雜度,一般是用來排序 0 到 100 之間的數(shù)字的最好的算法,但是它不適合按字母順序排序人名。

計(jì)數(shù)排序不是比較排序,排序的速度快于任何比較排序算法。

算法思想

找出待排序的數(shù)組中最大和最小的元素;

統(tǒng)計(jì)數(shù)組中每個值為 i 的元素出現(xiàn)的次數(shù),存入數(shù)組 C 的第 i 項(xiàng);

對所有的計(jì)數(shù)累加(從 C 中的第一個元素開始,每一項(xiàng)和前一項(xiàng)相加);

向填充目標(biāo)數(shù)組:將每個元素 i 放在新數(shù)組的第 C[i] 項(xiàng),每放一個元素就將 C[i] 減去 1;


計(jì)數(shù)排序動圖演示:

代碼:


9、桶排序

? ? ? ?將值為i的元素放入i號桶,最后依次把桶里的元素倒出來。

算法思想

設(shè)置一個定量的數(shù)組當(dāng)作空桶子。

尋訪序列,并且把項(xiàng)目一個一個放到對應(yīng)的桶子去。

對每個不是空的桶子進(jìn)行排序。

從不是空的桶子里把項(xiàng)目再放回原來的序列中。


桶排序動圖演示:

代碼:

function bucketSort(arr, bucketSize) {

if (arr.length === 0) {

return arr;

}

var i;

var minValue = arr[0];

var maxValue = arr[0];

for (i = 1; i < arr.length; i++) {

if (arr[i] < minValue) {

minValue = arr[i];? ? ? ? ? ? ? ? // 輸入數(shù)據(jù)的最小值

} else if (arr[i] > maxValue) {

maxValue = arr[i];? ? ? ? ? ? ? ? // 輸入數(shù)據(jù)的最大值

}

}

// 桶的初始化

var DEFAULT_BUCKET_SIZE = 5;? ? ? ? ? ? // 設(shè)置桶的默認(rèn)數(shù)量為5

bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;

var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;

var buckets = new Array(bucketCount);

for (i = 0; i < buckets.length; i++) {

buckets[i] = [];

}

// 利用映射函數(shù)將數(shù)據(jù)分配到各個桶中

for (i = 0; i < arr.length; i++) {

buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);

}

arr.length = 0;

for (i = 0; i < buckets.length; i++) {

insertionSort(buckets[i]);? ? ? ? ? ? ? ? ? ? ? // 對每個桶進(jìn)行排序,這里使用了插入排序

for (var j = 0; j < buckets[i].length; j++) {

arr.push(buckets[i][j]);

}

}

return arr;

}


10、基數(shù)排序

? ? ? ?一種多關(guān)鍵字的排序算法,可用桶排序?qū)崿F(xiàn)。

算法思想

取得數(shù)組中的最大數(shù),并取得位數(shù);

arr為原始數(shù)組,從最低位開始取每個位組成radix數(shù)組;

對radix進(jìn)行計(jì)數(shù)排序(利用計(jì)數(shù)排序適用于小范圍數(shù)的特點(diǎn))

基數(shù)排序動圖演示:

代碼:

int maxbit(int data[], int n) //輔助函數(shù),求數(shù)據(jù)的最大位數(shù)

{

int maxData = data[0];///< 最大數(shù)

/// 先求出最大數(shù),再求其位數(shù),這樣有原先依次每個數(shù)判斷其位數(shù),稍微優(yōu)化點(diǎn)。

for (int i = 1; i < n; ++i)

{

if (maxData < data[i])

maxData = data[i];

}

int d = 1;

int p = 10;

while (maxData >= p)

{

//p *= 10; // Maybe overflow

maxData /= 10;

++d;

}

return d;

/*? ? int d = 1; //保存最大的位數(shù)

int p = 10;

for(int i = 0; i < n; ++i)

{

while(data[i] >= p)

{

p *= 10;

++d;

}

}

return d;*/

}

void radixsort(int data[], int n) //基數(shù)排序

{

int d = maxbit(data, n);

int *tmp = new int[n];

int *count = new int[10]; //計(jì)數(shù)器

int i, j, k;

int radix = 1;

for(i = 1; i <= d; i++) //進(jìn)行d次排序

{

for(j = 0; j < 10; j++)

count[j] = 0; //每次分配前清空計(jì)數(shù)器

for(j = 0; j < n; j++)

{

k = (data[j] / radix) % 10; //統(tǒng)計(jì)每個桶中的記錄數(shù)

count[k]++;

}

for(j = 1; j < 10; j++)

count[j] = count[j - 1] + count[j]; //將tmp中的位置依次分配給每個桶

for(j = n - 1; j >= 0; j--) //將所有桶中記錄依次收集到tmp中

{

k = (data[j] / radix) % 10;

tmp[count[k] - 1] = data[j];

count[k]--;

}

for(j = 0; j < n; j++) //將臨時數(shù)組的內(nèi)容復(fù)制到data中

data[j] = tmp[j];

radix = radix * 10;

}

delete []tmp;

delete []count;

}


關(guān)注小編,編程學(xué)習(xí)不迷路!

如果你想要獲取更多C語言、C++、Windows以及QT的知識!

小編的專欄有一個免費(fèi)的C/C++編程學(xué)習(xí)交流俱樂部(群),【點(diǎn)擊進(jìn)入】

還有編程學(xué)習(xí)文件(源碼,項(xiàng)目實(shí)戰(zhàn)教學(xué)視頻以及給小白的零基礎(chǔ)教程),歡迎初學(xué)者和正在進(jìn)階中的小伙伴們!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容