对于几种排序算法,尤其是快排,堆排序和归并排序这种,真的是写了忘,忘了写,最近笔试遇到了链表排序,需要用到归并排序,又想起了数组的归并,发现自己还有地方都没有掌握透彻,也遇到了很多坑。
- 首先需要缕清整体思路,一个sort函数,递归将数组进行分割排序,一直到每一块数组长度都为1,这是我们需要确定递归的退出条件,判断条件是if(left<right),这样能够确保递归的结束,每一个递归都应有判断退出条件
- 在数字归并排序的过程中,我们需要有一个临时数组来存放已经排序好的数据,但是一定要注意,在一次归并的结尾需要将临时数组中已经排序好的数组,按照顺序复制到原数组中,因为我们的排序比较都是基于原数组实现的
- 我在写的时候,又牵扯到另外一个问题,就是拷贝怎么去确定位置呢?
我们可以将每次归并排序用来存放排序好数据的临时数组中的值进行覆盖,这样临时数组中每次拷贝是从0开始的,而原数组则是从参数L开始,到R结束,这里注意的另外一个点是,我们在数组合并时,使用的双指针不应该直接在参数上++,而是定义新的双指针,因为后续的L,R我们在拷贝时还会用到。
其实思路感觉自己已经摸清了,但是写代码时发现存在的细节还是蛮多的,下面是写的最基础的代码
//数组排序之归并排序
class Solution {
public:
vector<int> ans;
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
ans.resize(n, 0);
sort(nums, 0, n - 1);
return nums;
}
void sort(vector<int>& nums, int front, int tail)
{
if (front < tail)
{
int mid = (front + tail) / 2;
sort(nums, front, mid);
sort(nums, mid + 1, tail);
merge(nums, front, mid + 1, tail);
}
}
void merge(vector<int>& nums, int l, int m, int r)
{
int pos = m - 1;
int i = l;
int j = m;
int count = 0;
while (i <= pos && j<= r)
{
if (nums[i] <= nums[j])
{
ans[count++] = nums[i++];
}
else
ans[count++] = nums[j++];
}
while (i <= pos)
ans[count++] = nums[i++];
while (j <= r)
ans[count++] = nums[j++];
for (int i = 0; i < r - l + 1; ++i)
{
nums[l + i] = ans[i];
}
}
};