0 介绍
归并排序是一种常见的排序算法,时间复杂度
o
(
n
l
o
g
n
)
o(nlogn)
o(nlogn)。它是经典的分治算法的应用,学习这个算法,不仅仅是学习排序本身,更重要是体会分治思想。
下面谈谈具体的算法步骤。
1 合并两个有序数组
在我们介绍归并排序算法之前,不妨先考虑一下如何考虑如何合并两个有序数组的问题。这个问题在Leetcode88题也有,你不妨先练练手再回来。这个问题并不难,我们假设待归并的两个数组在同一个数组nums里,第一个数组的左右界限是left和rightEdge-1,第二个数组的左右界限为rightEdge和right。temp是用于辅助合并的数组,初始和nums值一样。那么我们只需要两个指针i,j分别从两个数组的左边界开始比较,将较小的数写入temp中,直到某个数组的值被遍历完,接着将剩下的值继续写入temp即可,最后将temp的值写入nums。实现代码如下:
void mergeArray(vector<int>&nums,vector<int>&temp,int left,int rightEdge,int right)
{
int leftEdge = rightEdge - 1;
int cur = left,i,j;
for(i = left,j = rightEdge; i <= leftEdge && j <= right; ++cur)
{
if(nums[i] <= nums[j])
temp[cur] = nums[i++];
else
temp[cur] = nums[j++];
}
if(i <= leftEdge)
{
for(; i <= leftEdge;i++)
temp[cur++] = nums[i];
}
else
{
for(; j <= rightEdge; j++)
temp[cur++] = nums[j];
}
for(int k = left; k <= right; ++k)//写回nums
nums[k] = temp[k];
}
2 实现归并排序
如果你完全了解合并两个有序数组的操作并能独立写出代码过了前面那道leetcode题,那么恭喜你距离掌握归并排序不远了。实现归并操作是使用了递归,它的思路是每次将待排序数组分为两份,分别递归进行排序,最后再将左右两边排好序的数组进行合并即可。代码虽只有短短几行,对递归函数不熟悉的朋友但是仔细琢磨起来却也很难。不妨从一些小数组开始思考,比如数组{5,2},使用mergeSort时实际直接进行了合并成了{2,5}。对于数组{5,2,7,3}来说,我们先是递归的排序{5,2}、{7,3},再把结果回溯上去合并{2,5}、{3,7}。对于大数组也可如此类推。代码实现如下:
void mergeSort(vector<int>& nums,vector<int>&temp,int left,int right)
{
if(left < right)
{
int mid = (left + right) / 2;
mergeSort(nums,temp,left,mid);
mergeSort(nums,temp,mid+1,right);
mergeArray(nums,temp,left,mid+1,right);
}
}