歸併排序是建立在歸併操作上的一種有效的排序算法。該算法是採用分治法(Divide and Conquer)的一個非常典型的應用,歸併排序將兩個已排序的表合併成一個表。
歸併排序基本原理:
通過對若干個有序結點序列的歸併來實現排序。
所謂歸併是指將若干個已排好序的部分合併成一個有序的部分。
歸併排序基本思想:
設兩個有序的子序列(相當於輸入序列)放在同一序列中相鄰的位置上:array[low..m],array[m + 1..high],先將它們合併到一個局部的暫存序列 temp (相當於輸出序列)中,待合併完成後將 temp 複製回 array[low..high]中,從而完成排序。
在具體的合併過程中,設置 i,j 和 p 三個指針,其初值分別指向這三個記錄區的起始位置。合併時依次比較 array[i] 和 array[j] 的關鍵字,取關鍵字較小(或較大)的記錄複製到 temp[p] 中,然後將被複制記錄的指針 i 或 j 加 1,以及指向複製位置的指針 p加 1。重複這一過程直至兩個輸入的子序列有一個已全部複製完畢(不妨稱其爲空),此時將另一非空的子序列中剩餘記錄依次複製到 array 中即可。
若將兩個有序表合併成一個有序表,稱爲2-路歸併。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void merge(int* array, int* temp, int first, int mid, int last)
{
int first_elm = first;
int second_elm = mid + 1;
int i = 0;
for(i = 0; first_elm <= mid && second_elm <= last; ++i)
{
if (array[first_elm] < array[second_elm])
{
temp[i] = array[first_elm];
++first_elm;
}
else
{
temp[i] = array[second_elm];
++second_elm;
}
}
for(; first_elm <= mid; ++first_elm, ++i)
{
temp[i] = array[first_elm];
}
for(; second_elm <= last; ++second_elm, ++i)
{
temp[i] = array[second_elm];
}
memcpy(array + first, temp, sizeof(int)*(last - first + 1));
}
void mergesort(int* array, int* temp, int first, int last)
{
if(first == last)
temp[first] = array[first];
else
{
int mid = first + (last - first)>>1;//使用減法防止移除,移位運算效率比除法效率高
mergesort(array, temp, first, mid);
mergesort(array, temp, mid + 1, last);
merge(array, temp, first, mid, last);
}
}
int main()
{
int i;
int array[] = {942, 12, 24, 87, 9, 475, 65, 17, 91, 1};
int size = sizeof(array);
int* temp = (int*)malloc(sizeof(array));
mergesort(array, temp, 0, 9);
for(i = 0; i < 10; i++)
{
printf("%d ", array[i]);
}
printf("\n");
free(temp);
return 0;
}
歸併排序時間複雜度爲最壞情況下和平均情況下複雜度均爲:O(nlogn),所需存儲空間爲:O(n)