目錄
2. 和選擇排序,冒泡排序等的暴力排序的區別在哪裏,爲什麼快?
瞭解其他常用算法點這裏 >> https://blog.csdn.net/GD_ONE/article/details/104061907
歸併排序是分治法思想的實例,學習完歸併排序後會更加理解分治法思想和遞歸思想。
- 什麼是歸併排序?
- 和選擇排序,冒泡排序的區別在哪裏,爲什麼它要比以上兩種排序快呢?
- 我們要怎麼實現歸併排序?
本文將主要解決以上三個問題。
1.什麼是歸併排序?
歸併排序的主要思想是:
1). 歸0
將無序的數列分爲兩個部分,對於每個部分,在繼續劃分爲更小的兩部分,直到每個部分都有序,即分解爲單個數據,因爲僅有一個數一定是有序的。
2). 合併
把每次分開的兩部分再合併到一起。合併是歸併排序的核心。
2. 和選擇排序,冒泡排序等的暴力排序的區別在哪裏,爲什麼快?
選擇排序和冒泡排序直接對原數列進行遍歷比較,要比較n+(n-1)+(n-2)...+1次,時間複雜度爲o(n^2)
歸併排序採用了分治法思想,將待排序的數列分解爲兩個更小的數列,分解數列的時間複雜度爲o(log2n),每一次分解都需要將兩個有序的數列合併在一起,合併兩個有序數列的時間複雜度是o(n)所以總的時間複雜度是 o(nlog2n)。
3. 代碼實現歸併排序
先看下圖, 圖來自https://www.cnblogs.com/onepixel/p/7674659.html
首先解決分的問題,需要將數列分爲兩個部分, 在將每個部分再次分爲兩個部分,直到不可再分。
我們可以使用遞歸的方式來實現歸併排序,其實分治法的思想幾乎就是遞歸的過程。
對於每一個序列,每次都按左右兩部分劃分,所以 int mid = l+r>>1;
然後對 (l, mid) 和 (mid + 1, r) 兩部分再次遞歸劃分。當l == r 時不再繼續劃分。
( 另: l+r >>1 是位運算, 相當於 (l+r)/ 2 )
代碼:
int mergesort(int a[], int l, int r){
if(l==r) return;
int mid = l+r>>1;
mergesort(a, l, mid);
mergesort(a, mid+1, r);
}
分完之後就剩下合併了
上面說到 將兩個有序的序列合併爲一個, 那麼怎麼合併呢, 首先我們當然需要一個額外的數組去存儲這個合併後的序列,
然後比較將兩個有序的序列的每一個數據,按照大小關係將數據存入額外數組。
如 1 3 5 和 2 4 6
先比較1 2 1 < 2 將1存入, 然後比較2 3 2 < 3 將2存入 以此類推。
完整代碼:
void mergesort(int a[], int l, int r){
if(l>=r) return;
int mid = l+r>>1;
mergesort(a, l, mid);
mergesort(a, mid+1, r);
int i,j,k = l;
for(i = l, j = mid + 1; i <= mid&&j <= r;){
if(a[i] > a[j]){
b[k++] = a[j];
j++;
}
else b[k++] = a[i], i++;
}
while(i <= mid) b[k++] = a[i++];
while(j <= r) b[k++] = a[j++];
for(int ii = l; ii <= r; ii++){
a[ii] = b[ii];
}
}