歸併排序
歸併排序是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法的一個非常典型的應用,它包含歸(遞歸)並(合併)兩個操作。
原理
先思考怎麼把兩個有序的序列A,B組合成一個新的有序序列C。
1. 取兩個序列A,B的第一個元素
2. 這樣序列A中的第一個元素變爲
3. 將A,B中還存在元素的序列中的元素,按順序添加到序列C的後面,這樣就完成了兩個有序序列的合併。
現在我們有一個亂序數組A,想把其中的元素排序,我們可以考慮把A從中值處分隔成兩個數組B和C,對B和C分別排序之後,將他們合併成一個用上面的方法合併成一個新的有序數組。
我們發現,如果數組只有一個元素的話,那它肯定是一個有序數組,所以我們可以對B和C再進行拆分,對拆分出來的數組繼續拆分直到所有的子數組都只有一個元素爲止,這樣所有的子數組都是有序的,對它們兩兩進行合併,最後終將可以合併成一個有序的數組。
示例
- 假設有數組
{3,5,4,2,1} - 第一次拆分
{3,5,4} {2,1} - 再一次拆分
{3,5} {4} {2} {1} - 再一次拆分
{3} {5} {4} {2} {1} - 合併
{3} {5} 爲{3,5} - 合併
{3,5} {4} 爲{3,4,5} - 合併
{2} {1} 爲{1,2} - 合併
{3,4,5} {1,2} 爲{1,2,3,4,5}
代碼
//合併有序數組
void mergeArray(int* arr, int left, int mid, int right, int* temp)
{
int i = left, j = mid + 1;
int k = 0;
while(i <= mid && j <= right) {
if(arr[i] < arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while(i <= mid) {
temp[k++] = arr[i++];
}
while(j <= right) {
temp[k++] = arr[j++];
}
for(int p = 0; p < k; p++) {
arr[left + p] = temp[p];
}
}
//遞歸拆分數組爲元素只有1個的有序數組
void mergeSort(int* arr, int left, int right, int* temp)
{
if(left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
mergeArray(arr, left, mid, right, temp);
}
}
void mergeSort(int* arr, int len)
{
int* temp = (int*)malloc(sizeof(int) * len);
mergeSort(arr, 0, len - 1, temp);
}
時間複雜度
歸併排序的時間複雜度爲