合并排序(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(len*sizeof(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;
}