基本思想:
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列之间都有序。若将两个有序表合并成一个有序表,称为二路归并。
具体实现(递归版本):
我们先创建一个和a大小相同的数组,因为有数组a和个数n是不够的,所以创建一个_MergeSort()作为MergeSort()的一个子函数来控制开头(begin)和结尾(end),先取中间值坐标,若中间值坐标的左右两个数组都有序,那么取两个数组中小的尾插,最后再拷贝回原数组归并哪部分就拷贝哪部分回去。我们发现递归在这里非常神奇!
实现代码:
void _MergeSort(int* a, int begin, int end, int* tmp)
{
if (begin == end)
return;
int mid = (end + begin) / 2;
// [begin, mid] [mid+1, end]
_MergeSort(a, begin, mid, tmp);
_MergeSort(a, mid+1, end, tmp);
// 取小的尾插
// [begin, mid] [mid+1, end]
int begin1 = begin, end1 = mid;
int begin2 = mid+1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
// 拷贝回原数组 -- 归并哪部分就拷贝哪部分回去
memcpy(a+begin, tmp+begin, (end-begin+1)*sizeof(int));
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int)*n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
tmp = NULL;
}
最后是一张动图:他这里是从底层往最高层演示的
归并排序的特性总结:
- 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
- 时间复杂度:O(N*logN)
- 空间复杂度:O(N)
- 稳定性:稳定