合併排序(MERGE SORT)是又一類不同的排序方法,合併的含義就是將兩個或兩個以上的有序數據序列合併成一個新的有序數據序列,因此它又叫歸併算法。它的基本思想就是假設數組A有N個元素,那麼可以看成數組A是又N個有序的子序列組成,每個子序列的長度爲1,然後再兩兩合併,得到了一個 N/2 個長度爲2或1的有序子序列,再兩兩合併,如此重複,值得得到一個長度爲N的有序數據序列爲止,這種排序方法稱爲2—路合併排序。
例如數組A有7個數據,分別是: 49 38 65 97 76 13 27,那麼採用歸併排序算法的操作過程如圖7所示:
初始值 [49] [38] [65] [97] [76] [13] [27]
看成由長度爲1的7個子序列組成
第一次合併之後 [38 49] [65 97] [13 76] [27]
看成由長度爲1或2的4個子序列組成
第二次合併之後 [38 49 65 97] [13 27 76]
看成由長度爲4或3的2個子序列組成
第三次合併之後 [13 27 38 49 65 76 97]
合併算法的核心操作就是將一維數組中前後相鄰的兩個兩個有序序列合併成一個有序序列。合併算法也可以採用遞歸算法來實現,形式上較爲簡單,但實用性很差。合併算法的合併次數是一個非常重要的量,根據計算當數組中有3到4個元素時,合併次數是2次,當有5到8個元素時,合併次數是3次,當有9到16個元素時,合併次數是4次,按照這一規律,當有N個子序列時可以推斷出合併的次數是X(2 >=N,符合此條件的最小那個X)。
其時間複雜度爲:O(nlogn).所需輔助存儲空間爲:O(n)
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
static void Merge(int *arr,int len,int gap)//一次歸併排序
{
int *brr = (int )malloc(lensizeof(int));
assert(brr != NULL);
int i = 0;//brr下標
int low1 = 0;//第一個歸併段的起始下標,下標可取
int high1 = low1 + gap - 1;//第一個歸併段的結束下標,下標可取
int low2 = high1 + 1;//第二個歸併段的起始下標,下標可取
int high2 = low2 + gap - 1 < len - 1 ? low2 +gap - 1 : len - 1;//第二個歸併段的起始下標,下標可取
while(low2 < len)
{
//兩個歸併段都有數據
while(low1 <= high1 && low2 <= high2)
{
if(arr[low1] <= arr[low2])
{
brr[i++] = arr[low1++];
}
else
{
brr[i++] = arr[low2++];
}
}
//有一個歸併段沒有數據,另一個還有數據
while(low1 <= high1)
{
brr[i++] = arr[low1++];
}
while(low2 <= high2)
{
brr[i++] = arr[low2++];
}
low1 = high2 + 1;
high1 = low1 + gap - 1;
low2 = high1 + 1;
high2 = low2 + gap - 1 < len - 1 ? low2 +gap - 1 : len - 1;
}
while(low1 < len)
{
brr[i++] = arr[low1++];
}
for(i = 0; i < len; i++)
{
arr[i] = brr[i];
}
free(brr);
}
void MergeSort(int* arr,int len)
{
for(int i = 1;i < len;i *= 2)
{
Merge(arr,len,i);
}
}
void Show(int *arr,int len)
{
for(int i = 0;i < len;i++)
{
printf("%d “,arr[i]);
}
printf(”\n");
}
int main()
{
int arr[] = {12,34,56,78,90,111,2,5,67,88,89,77,-2};
MergeSort(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}