介绍
归并排序(Merging Sort)就是利用归并的思想实现的排序方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到⌈n/2⌉(⌈x⌉表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。
一开始,我们把每两两个数据看成排好的序列,就能实现归并了,这也是递归的出口。所以一开始的递归入口是把数据分成两半,一直递归调用归并排序,最终就会触发两两数据就是两个序列的出口条件。(写过代码,理解这句不难,没写过就难了)
这张图直接从递归最深处开始画了。
代码
//辅助函数:交换两个变量
void swap(int*a,int*p)
{
int temp = *a;
*a = *p;
*p = temp;
}
//归并排序
//本质上是把两个已经排好的序列合并成一个
//如果对一个随机序列的两两元素来看,那么每个元素都是排好的序列
//可以把一个数组拆分成前后两半来做这件事
//这个算法需要额外的辅助空间,用来存放归并好的结果
void mergeSort(int* arr,int start,int end)
{
if(start>=end)
{
return;
}
int i = start;
int mid = (start+end)/2;
int j = mid + 1;
mergeSort(arr,i,mid);
mergeSort(arr,j,end);
//合并
//其实我觉得不用这个额外的空间也行,两个子序列再排一次能减少空间,不过速度肯定会有影响
int* temp = (int*)malloc((end-start+1)*sizeof(int));
int index = 0;
//开始对比两个子序列,头部最小的那个数放到新空间
while(i<=mid&&j<=end)
{
if(arr[i]<=arr[j])
{
temp[index++] = arr[i++];
}else
{
temp[index++] = arr[j++];
}
}
//总有一个序列是还没有放完的,这里再遍历一下没放完的
while(i<=mid)
{
temp[index++] = arr[i++];
}
while(j<=end)
{
temp[index++] = arr[j++];
}
//排完再把新空间的元素放回旧空间
int k = start;
for(k;k<=end;k++)
{
//哎,temp的下标写错,排查了一个钟,真菜
arr[k] = temp[k-start];
}
free(temp);
}