- 简介
归并排序是冯诺依曼在1945年提出的一种有效的排序算法。它的时间复杂度是O(nlogn),空间复杂度O(n),它是一个稳定的排序。
- 思想
正如它的名字,归并排序是建立在归并操作上的。所谓归并就是将两个已排序序列合并成为一个序列的操作。对于归并我们使用一个函数(Merge)来实现,具体步骤如下:
①首先申请空间,大小为两个已排序序列之和;
②定义两个指针,分别指向两个序列的起始位置;
③比较两个指针指向的元素,选择较小的放入合并空间,并将指针后移一位;
④重复步骤③,直至有一个指针走到末尾;
⑤直接将剩下的序列中的元素复制到合并空间。
归并排序的实现方式有 递归实现 和 非递归实现 两种实现方式。
递归实现:自顶向下,是分治法的典型应用。将一个大问题分为小问题,用所有小问题的答案来解决大问题。
非递归实现(迭代):自底向上,两两归并---四四归并---八八归并...直到归并整个数组。
- 具体代码(数组实现,升序,2种实现方式)
归并函数:
void Merge(int arr[],int left,int mid,int right)
{
int len = right - left + 1;
int *p = (int *)malloc(len*sizeof(int));
int i = left;
int j = mid + 1;
int index = 0;
while(i <= mid && j <= right)
{p[index++] = arr[i] <= arr[j]?arr[i++]:arr[j++];} //等于号保证了稳定性
while(i <= mid)
{p[index++] = arr[i++];}
while(j <= right)
{p[index+=] = arr[j++];}
for(int k = 0; k < len ; k++)
{arr[k++] = p[k];}
}
归并的递归实现(自顶向下):
void MergeSortRecursion(int arr[],int left,int right)
{
int mid = (left + right)/2;
if(left == right) return; //直到递归至只剩一个数时,退出本轮
MergeSortRecursion(arr,left,mid); //将左半边不断划分至两两一组
MergeSortRecursion(arr,mid+1,right); //将右半边划分
Merge(arr,left,mid,right); //将本轮左右排好序的进行归并
}
归并的非递归实现(自底向上):
void MergeSortIteration(int arr[],int len)
{
int left,mid,right;
for(int i = 1; i < len; i*=2)
{
left = 0;
while(left + i < len) //left+i代表后一数组的起始(如果存在)
{
mid = left + i - 1; //准备进行归并,left+i == mid + 1,得出mid
right = mid + i > len? mid + i: len - 1; //设定右边界,有可能超过数组大小
Merge(arr,left,mid,right);
left = right+1; //进行下一轮
}
}
}