日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

九种排序方法辨析

發(fā)布時間:2025/3/15 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 九种排序方法辨析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

??????雖然網(wǎng)上有很多關(guān)于排序的文章,但那畢竟是別人。還是決定自己寫一寫,說不定會發(fā)現(xiàn)新的東西。如有錯誤,請務(wù)必指正!

??????目前為止學(xué)過的排序依次包括:冒泡排序,選擇排序,插入排序,希爾排序,快速排序,歸并排序,堆排序,基數(shù)排序,計數(shù)排序。

??????注:在每種排序后都注明該排序方法的穩(wěn)定性。所謂穩(wěn)定性就是排序前后兩個相同元素的位置是否發(fā)生改變。若不變則是穩(wěn)定排序,改變則是不穩(wěn)定排序。規(guī)定本文中所有排序方式為從小到大排序。

1. 冒泡排序(穩(wěn)定排序)

??????冒泡排序的思想是比較兩個相鄰元素,若后面的元素更小則交換兩個元素的位置,以此類推。每次迭代過后,當前序列中最大的元素就被置于末尾。
??????冒泡排序的時間復(fù)雜度是O(n2),最好情況是已經(jīng)有序,時間復(fù)雜度降至O(n)。

代碼如下:

Status Bubble_Sort(int a[MAXSIZE+1]) { int i, j, temp; for (i=1; i<=MAXSIZE; i++) { //注意i, j相差的是一個i for (j=1; j<=MAXSIZE-i; j++) { if (a[j] > a[j+1]) { temp = a[j];a[j] = a[j+1]; a[j+1] = temp; }} } return OK; }

2. 選擇排序(不穩(wěn)定排序)

??????選擇排序的思想是比較選擇當前序列中最大的元素與序列中最后一個元素做交換。特點是要保留最大元素的位置。
??????選擇排序的時間復(fù)雜度是O(n2),最好情況是已經(jīng)有序,時間復(fù)雜度降至O(n)。
代碼如下:

Status Choose_Sort(int a[MAXSIZE+1]) { int i, j, temp; int minlocation, minnum;//minnum用于存儲最小值,minlocation用于存儲最小值位置 for (i=1; i<=MAXSIZE; i++) { minlocation = i; minnum = a[i]; for (j=i; j<=MAXSIZE; j++) { if (a[j] < minnum) { minnum = a[j];minlocation = j;} } temp = a[minlocation]; a[minlocation] = a[i]; a[i] = temp; } return OK; }

3. 插入排序(穩(wěn)定排序)

??????插入排序的思想是,把當前元素與之前的每個元素作比較直至出現(xiàn)當前元素大于之前元素的情況。同時在比較過程中,對比較過但不合適的元素右移。在比較前做一個特殊處理:若當前元素小于前一個元素才進入循環(huán)作比較,否則說明為當前最大直接放在最后即可。
??????插入排序的時間復(fù)雜度是O(n2),最好情況是已經(jīng)有序,時間復(fù)雜度降低至O(n)。
代碼如下:

Status Insert_Sort(int a[MAXSIZE+1]) { //實現(xiàn)插入排序,插入方法是從第二個元素往后每次和前面的進行比較。如果前面的比原來的大,則將 //大的向后移動,繼續(xù)比較直到尋找到合適目標為止 int i, j; for (i=2; i<=MAXSIZE; ++i) { if (a[i] < a[i-1]) { //先進行一個判斷,如果是最大的就不用繼續(xù)再比了。減少比較次數(shù) a[0] = a[i]; a[i] = a[i-1]; for (j=i-2; a[j]>a[0]; j--){ a[j+1] = a[j];} a[j+1] = a[0]; } } return OK; }

4. 希爾排序(不穩(wěn)定排序):

??????希爾排序是插入排序的改進算法,調(diào)整了每次前移的距離。并在每輪迭代的時候?qū)⑶耙凭嚯x減少,最終下降至1。特點是需要提前準備好前移序列。
??????希爾排序不穩(wěn)定的原因:一次插入排序是穩(wěn)定的,但多次使用插入排序可能會改變相同元素的相對位置。所以希爾排序是不穩(wěn)定排序。
??????希爾排序的平均時間復(fù)雜度是O(nlogn),不過也取決于前移序列的選擇。上網(wǎng)查閱資料后得知,希爾排序的研究還未停止。時間復(fù)雜度分布在O(nlogn-n2)。
代碼如下:

Status Shell_Sort1(int a[MAXSIZE+1]) { //Shell_Sort1主要進行輪數(shù)的確定,即確定幾輪幾個間隔 //設(shè)定為5輪, 分別為,9、7、5、3、1 int intervel[5] = {9, 7, 5, 3, 1}; for (int i=0; i<5; i++) { Shell_Sort2(a, intervel[i]); }return OK; } Status Shell_Sort2(int a[MAXSIZE+1], int intervel) { //Shell_Sort主要進行間隔數(shù)的調(diào)整 int i, j; for (i=intervel+1; i<=MAXSIZE; i++) { if (a[i] < a[i-intervel]) { a[0] = a[i]; for (j = i-intervel; j>0 && a[j]>a[0]; j -= intervel) { a[j+intervel] = a[j];} a[j+intervel] = a[0]; } } return OK; }

5. 快速排序(不穩(wěn)定排序):

?????? 快速排序的思想是遞歸選取一個中心點(常選取中心點是序列的第一個元素),將小于中心的值移動到左邊,將大于中心的值移動到右邊。
??????快速排序的平均時間復(fù)雜度是O(nlogn),影響時間復(fù)雜度的是中心點的選取,即左右兩邊的比重。最壞情況是選取一邊沒有元素的中心點,這樣時間復(fù)雜度下降至O(n2)。最優(yōu)情況是選取得中心點恰好是序列的中心點,時間復(fù)雜度為O(nlogn)。可證當選取中心點出現(xiàn)左邊1個,右邊n個的情況時間復(fù)雜度也為O(nlogn)。說明快速排序的壞情況是間隔出現(xiàn)的有兩種方式可以解決這個問題:1.不選取序列第一個元素,改為隨機選取。2.打亂當前序列。經(jīng)過驗證第二種方式的實際效果更好??梢允褂秒S機化算法,先將序列打亂順序再使用快速排序。這樣時間復(fù)雜度可穩(wěn)定在O(nlogn)。
代碼如下:

Status Quick_Sort(int a[MAXSIZE+1], int low, int high) { int tag; if (low < high) { tag = Tag(a, low, high);Quick_Sort(a, low, tag-1);Quick_Sort(a, tag+1, high); }return OK; } int Tag(int a[MAXSIZE+1], int low, int high) { //tag取最左側(cè)元素,作為標記位,會被移到中間去。左邊會比tag小,右邊會比tag大 int tag; tag = a[low]; while (low < high) { while (low < high && a[high] >= tag){ //此處必須包含等于,等于的情況下也是應(yīng)該移動的,如果等于發(fā)生交換那么后序無法進行 high--; } a[low] = a[high]; while (low < high && a[low] <= tag){ //在移動過程中要時刻判斷l(xiāng)ow和high的關(guān)系,可能在Low++后已經(jīng)超過,但依舊循環(huán) low++; } a[high] = a[low]; } a[low] = tag; return low; }

6. 歸并排序(穩(wěn)定排序):

??????歸并排序的思想是將序列遞歸分治,分解至最小模塊后。不斷歸并有序序列,最終得到整體有序。
??????歸并排序是穩(wěn)定排序的原因:保持歸并排序的穩(wěn)定性可做特殊處理,保證兩組有序序列merge時按照前后兩個序列的先后順序插入即可維持穩(wěn)定。
??????歸并排序的時間復(fù)雜度是O(nlogn)。最好最壞的情況都是O(nlogn)。因為歸并排序?qū)訑?shù)都是logn向下取整。整體merge都是n。特點是比較穩(wěn)定,不受輸入序列順序的影響。但需要O(n)的空間復(fù)雜度。
代碼如下:

Status Merge_Insert(int *temp_merge, int *merge, int s, int m, int t) { //具體歸并的過程類似于,將兩個鏈表在遍歷一次的情況下合成到另一個鏈表上去,一次移動一位 int i, j, k; for (i=s, j=m+1,k=s; i<=m&&j<=t; ++k) { if (temp_merge[i] < temp_merge[j]){ merge[k] = temp_merge[i++];} else { merge[k] = temp_merge[j++];} } //進行補位,若哪半邊還有剩余的直接依次補齊 if (i > m) { while (j <= t) { merge[k++] = temp_merge[j++];} } if (j > t) { while (i <= m) { merge[k++] = temp_merge[i++];} } } Status Merge_Sort(int a[MAXSIZE+1], int *merge, int s, int t) { if (s == t) { //先進行一次判斷,若只有一個元素則直接輸出即可 merge[s] = a[s]; } else { int m; int temp_merge[MAXSIZE+1]; m = (s + t)/2; Merge_Sort(a, temp_merge, s, m);//將temp_merge的前半部分歸并有序,并將temp_merge的后半部分歸并有序 Merge_Sort(a, temp_merge, m+1, t);Merge_Insert(temp_merge, merge, s, m, t);//最后將兩部分有序的統(tǒng)一歸并到merge中 } return OK; }

7. 堆排序(不穩(wěn)定排序):

??????堆排序思想使用堆的數(shù)據(jù)結(jié)構(gòu)(前面有過專門的文章介紹堆,有需要的朋友可以去看看)。使用最小/大堆,每次將堆頂?shù)脑胤诺胶线m的位置。堆排序共有兩步:將堆頂元素放于合適位置->重新將堆調(diào)整至最小/大堆。
??????堆排序的時間復(fù)雜度是O(nlogn),堆排序的過程包括構(gòu)造堆和取出兩步,最好最壞時間復(fù)雜度都是O(nlogn)。兩者相差是常數(shù)級別。
代碼如下:

Status Heap_Sort(int a[MAXSIZE+1]) { int temp; //先將普通數(shù)組調(diào)成大頂堆 for (int i=MAXSIZE/2; i>0 ; i--) { Heap_Insert(a, i, MAXSIZE); } for (int i=MAXSIZE; i>1; i--) { //每次重新調(diào)整成大頂堆,并且將第一個元素移到最后 temp = a[1]; a[1] = a[i]; a[i] = temp; Heap_Insert(a, 1, i-1); } return OK; } Status Heap_Insert(int a[MAXSIZE+1], int s, int m) { int temp = a[s];//最開始第一個元素不滿足條件,其余滿足。將該元素暫存 for (int j=2*s; j<=m; j *= 2)//j是s的子節(jié)點,必須是s的二倍 { //選擇左右子樹大的那一個 if (j<m && a[j] < a[j+1]) { j++; } if (temp >= a[j]) { //當標記元素比當前元素大(即比當前元素的兄弟都大),即可放入雙親節(jié)點break; } a[s] = a[j];//s就是j的雙親,每次j移動,s跟上 s = j; } a[s] = temp; return OK; }

8. 基數(shù)排序(穩(wěn)定排序)

??????基數(shù)排序的思想是從最低位開始排序,依次向前移動且不改變相同值的相對位置??梢允褂面湵韥韺崿F(xiàn),留出10個(0,1,。。。9)空間按照最低位放入空間再連接完成一次迭代。
??????基數(shù)排序的時間復(fù)雜度是O(n)。之前很困惑為什么基數(shù)排序的時間復(fù)雜度比快速排序更低,但是卻沒有快速排序常用。經(jīng)過查找資料得出原因:基數(shù)排序的時間復(fù)雜度實際是O(kn)。且常數(shù)K的值往往很大,而快速排序的常數(shù)值很小。并且基數(shù)排序也是相對比較消耗空間的。大多數(shù)應(yīng)用條件下使用快速排序更佳。
代碼如下:

Status Radix_Sort(int a[MAXSIZE+1]) { //基數(shù)排序,每輪即從個位向前進行排序。使用隊列的存儲形式。 //建立一個總的隊列元素個數(shù)為MAXSIZE+2,使用順式結(jié)構(gòu)循環(huán)隊列 //同時建立十個(0-9)隊列數(shù)組,編號即代表位數(shù)。當從總隊列遍歷時,進入對應(yīng)的隊列數(shù)組。全部完成后 //清空總隊列,將各個隊列數(shù)組元素依次進入總隊列 int temp;//temp用來存儲當前對應(yīng)的一位數(shù)字 int afterpow; Queue Ten[10]; for (int i=0; i<10; i++) { InitQueue(Ten[i]); } for (int i=0; i<5; i++) { //本次樣本中,沒有超過五位數(shù)的,進行五輪就可以 for (int j=1; j<=MAXSIZE+1; j++) { afterpow = pow(10, i); temp = (a[j] / afterpow) % 10;EnQueue(Ten[temp], a[j]); } for (int j=1; j<=MAXSIZE+1; ) { for (int i=0; i<10; i++) { while (Ten[i].rear != Ten[i].front){ DeQueue(Ten[i], temp);//此處temp起轉(zhuǎn)移作用 a[j++] = temp; } } } for (int i=0; i<10; i++) { //每次完成之后,將數(shù)組隊列清空 Ten[i].front = 0; Ten[i].rear = 0; } } return OK; }

9. 計數(shù)排序(不穩(wěn)定排序):

??????計數(shù)排序的思想是,統(tǒng)計最小元素到最大元素之間每個序列中每個出現(xiàn)的元素個數(shù)并制成表。表中包括每個元素開始的位置,是前一項的起始頂點加前一項的個數(shù)得到。再遍歷一遍原序列,按照表中位置直接插入指定位置。并動態(tài)更新表。
?????? 計數(shù)排序的時間復(fù)雜度是O(n),不過計數(shù)排序只適用于最大元素不是特別大的情況,原因在于需要保留最小元素到最大元素中每一個元素的個數(shù),有的元素個數(shù)為0但仍要占空間。

??????排序方法的選擇更多的是依靠實際序列的特點和規(guī)模。對于規(guī)模變化大的序列排序,可以使用混合的方法,只要計算出臨界值即可。

??????排序真是編程中最基本的操作之一了,不過這么多方法完全弄懂也是有一定難度的。老師說過:對于排序算法要考慮N無窮的情況,切不可貪圖方便只使用O(n2)的方法啦!

因本文作者水平有限,如有問題,請各位高手在下方評論區(qū)指正,謝謝!

總結(jié)

以上是生活随笔為你收集整理的九种排序方法辨析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。