归并算法的基本思想:
就是两个有序子集之间通过合并成一个大的有序集
然后合并的这个大的有序集再与另一个大的有序集继续合并成更大的有序集
直到完成整个数组的有序
举个例子:数组 [5,3,2,6]
1. 划分为两个子集
2. 分别有序化
3. 合并过程,分别用两个指针,依次对比子集间的元素大小,填充到额外的空间
4. 将有序话的额外空间再次填充回原数组
过程 2 其实就是 过程 1,3,4 的一个过程
我们来看下代码实现:
把数组一分为二,分别对左边,右边排序,最后再通过合并方式让整体有序
void doMergeSort(int *arr, int l, int r)
{
if(l == r)
return;
int mid = l + ((r - l) >> 1);
doMergeSort(arr, l, mid);
doMergeSort(arr, mid+1, r);
mergeArr(arr, l, mid, r);
}
合并部分用双指针,以及额外空间将数组有序化
1) 这个部分要特别注意
void mergeArr(int *arr, int l, int mid, int r)
{
int i = 0;
int p1 = l;
int p2 = mid + 1;
int len = r - l + 1;
int *help = (int *)malloc(sizeof(int) * len);
while(p1 <= mid && p2 <= r)
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
while(p1 <= mid)
help[i++] = arr[p1++];
while(p2 <= r)
help[i++] = arr[p2++];
for(i=0; i<len; i++)
arr[l+i] = help[i]; // 1
free(help);
}
最后是入口调用部分,简单排他一下
void mergeSort(int *arr, int len)
{
if(arr == NULL || len < 2)
return;
int l = 0;
int r = len - 1;
doMergeSort(arr, l, r);
}
时间复杂度是 O(N * logN),额外空间复杂度 O(N)
可以参考递归时间复杂度如何计算的: