喜歡看排序算法動態效果的,可以看看這個網站
https://visualgo.net/zh/sorting
里面很多算法的動畫解釋,可以看到算法的排序效果,而且還附帶了偽代碼的實現過程。
本來想錄制幾張動圖放上來,但是因為圖片較大,傳不上來,公眾號對動態圖片有限制,喜歡的同學可以點擊我上面的鏈接,自己去嘗試一下。
我畫了一個圖片,用來表示歸并排序的運算過程
排序的過程
先把需要排序的數據分成兩份。
把兩份的數據依次進行排序并組合在一起。
再把排序后的兩組數據進行并入一起排序。
好了,寫代碼吧
我們先實現,「把兩份的數據依次進行排序并組合在一起」
下面是實現這個的算法過程
/**?r[]?:?需要排序的數組*?s[]?:?排序后保存數據的數組*?left:?排序的起始位置*?mid?:?排序的中間位置*?right:排序的最右邊位置*/
int?merge(int?r[],int?s[],int?left,int?mid,int?right)
{int?i,j,k;i=left;j=mid+1;k=left;for(;i?<=?mid?&&?j<=right;){if(r[i]<=r[j])s[k]?=?r[i++];elses[k]?=?r[j++];k++;}for(;i<=mid;)s[k++]=r[i++];for(;j<=right;)s[k++]=r[j++];return?0;
}
如果我們對兩個數進行排序
經過上面的那個函數排序后,我們會把[3,1]排序成[1,3]。
——
那,如果我們需要對4個數字進行排序呢?
我們需要先把4個數字分成2組
然后,我們需要依次對上面的兩組數據進行排序,得到下面新的兩組數據
然后,我們需要把已經排序的兩個數組進行排序
s[]?是保存的排序結果,r[] 是需要排序的數組。
left,mid,right 是排序數組中的三個位置。
left = 0;
right = 3;
mid = ( left + right )/2 =?1;
進入函數體,我們需要三個變量來協助我們進行運算
i = left = 0;
j = mid +1 =?1 +1 = 2;
k = left = 0;
它們看起來是這樣子的
把r[i]?和 r[j]?兩個數進行比較,把小的那個數放到s[k] 里面,然后再移位
比較之后變成
然后再執行下面的代碼
for(;i?<=?mid?&&?j<=right;){if(r[i]<=r[j])s[k]?=?r[i++];elses[k]?=?r[j++];k++;
}
這時候 j = 4
這時候就退出了 for 循環
退出for 循環后 就開始執行下面的 for 循環
?for(;i<=mid;)s[k++]=r[i++];for(;j<=right;)s[k++]=r[j++];
這樣后,會變成這樣
這樣就退出 merge 函數
經過上面的過程,我們需要應該有點悟性,我們需要使用遞歸來解決這些問題
可以看下面的文章了解啥是遞歸
C 語言,你真的懂遞歸了嗎?
然后呢,我們就寫了一個這樣的遞歸函數,放心吧,在學習樹的時候,也是需要這種遞歸操作的。
/**?r[]?:?需要排序的數組*?s[]?:?排序后保存數據的數組*?left:?排序的起始位置*?right:排序的最右邊位置*/
int?merge_sort(int?r[],int?s[],int?left,int?right)
{int?mid;int?t[20];if(left==right)s[left]=r[right];else{mid=(left+right)/2;merge_sort(r,t,left,mid);/*sort?left~mid*/merge_sort(r,t,mid+1,right);/*sort?mid+1~right*/merge(t,s,left,mid,right);/*merge?sort?left,mid,right*/}return?0;
}
這個函數就是遞歸函數,遞歸最后退出機制是?
left?==?right?
再然后,我們需要一個?main 函數
完整的代碼實現如下
#include?<stdio.h>
#include?<stdlib.h>/**?r[]?:?需要排序的數組*?s[]?:?排序后保存數據的數組*?left:?排序的起始位置*?mid?:?排序的中間位置*?right:排序的最右邊位置*/
int?merge(int?r[],int?s[],int?left,int?mid,int?right)
{int?i,j,k;i=left;j=mid+1;k=left;for(;i?<=?mid?&&?j<=right;){if(r[i]<=r[j])s[k]?=?r[i++];elses[k]?=?r[j++];k++;}for(;i<=mid;)s[k++]=r[i++];for(;j<=right;)s[k++]=r[j++];return?0;
}/**?r[]?:?需要排序的數組*?s[]?:?排序后保存數據的數組*?left:?排序的起始位置*?right:排序的最右邊位置*/
int?merge_sort(int?r[],int?s[],int?left,int?right)
{int?mid;int?t[20];if(left==right)s[left]=r[right];else{mid=(left+right)/2;merge_sort(r,t,left,mid);/*sort?left~mid*/merge_sort(r,t,mid+1,right);/*sort?mid+1~right*/merge(t,s,left,mid,right);/*merge?sort?left,mid,right*/}return?0;
}int?main()
{int?a[8]?=?{6,5,3,1,8,7,2,4};int?i;merge_sort(a,a,0,7);for(i=0;i<sizeof(a)/sizeof(a[0]);i++)printf("%d?",a[i]);printf("\n");return?0;
}
程序輸出
1?2?3?4?5?6?7?8
算法復雜度,翻開以前寫的文章
時間復雜度和空間復雜度,一看就懂,面試前必過一遍
中間是?mid =?(left+right)/2?
可以猜到是 O(logN) ,也就是排序的時間是用logN時間去拆分的,而且拆分的時候,我們還需要進行排序,也就是代碼里面提到的,排序的時間是O(n),所以在拆分和排序中需要花費的時間是 O(NlogN)。
拆分需要花費 O(logN) ,那合并的時候自然也需要花費O(logN)
總的算法時間是
O(NlogN + logN)??=?O(NlogN)
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識小密圈
關注公眾號,后臺回復「1024」獲取學習資料網盤鏈接。
歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~
總結
以上是生活随笔為你收集整理的C语言,谁都能看得懂的归并排序的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。