🎗️ 主页:小夜时雨
🎗️专栏:归并排序
🎗️如何活着,是我找寻的方向
目录
- 1. 题目解析
- 2. 代码
1. 题目解析
题目链接: https://leetcode.cn/problems/sort-an-array/
我们上道题讲过归并排序的核心代码,建议先看一下这道题:合并两个有序数组 https://leetcode.cn/problems/merge-sorted-array/description/
归并排序的核心代码区间就是合并两个有序数组, 所以还是十分重要的, 接下来我们再来分析一下合并这个过程:
- 首先这两个是非递减的整数数组,那么很自然的一个想法就是从头开始遍历两个数组,谁小取出来排队即可。
- 取出来排队这个操作我们巨化为创建一个辅助数组,将数组中二者比较小的放入到这个辅助数组中, 直到遍历结束。
- 最后再将辅助数组拷贝到原始数组中即可。整体的思路还是比较符合实际我们进行比较排序的情况的。
接下来我们来说一下归并排序的实现过程
归并排序具体实现过程:
- 首先我们先确定一个 key,把数组分为左右两个区间进行排序,此处通常都是选为中间区域,key = (left + right)/ 2 。
- 左右区间在进行排序,怎么排序:同样是在左区间找一个key,使得左区间又分为左右两个区间,同理右区间也是。我们发现都是先进行划分区间,一直划分。
- 划分直到左右区间内只有一个元素或者区间不存在,假设只有一个元素,那么不用排序天然就是有序的,此时要做的就是归并排序的核心操作:把左右区间的两个元素继续有序的合并,合并成一个有序的区间向上返回。
- 也就是说我们一直划分到划分不了区间为止,然后开始合并变成有序向上返回,越往上返回此时的数组也就是越有序的,直到最后的两个左右有序区间进行合并,那么最后这个区间就是有序的了,也就是排好序了。
看下面的分析图可能会更容易理解:
- 也就是说我们想先排整体有序,以左区间为例:得先让左区间进行有序,让左区间有序就得让左区间的左右区间进行有序,然后合并,
- 就这样一直划分下去,直到划分不了区间。我们发现这个过程其实有点像是二叉树的后序遍历,左右区间有序之后(类比先遍历左右子树),合并之后整体才会有序(遍历根节点)。
- 接下来,后面会写到快排,快排则是相反的一个过程,类似于二叉树的前序遍历,后面很快会写到。
2. 代码
看下面的代码对照着上面的流程解析可能会更加的清楚。
int[] tmp; // 用一个全局的辅助数组
public int[] sortArray(int[] nums) {
int n = nums.length;
tmp = new int[n];
mergeSort(0, n - 1, nums);
return nums;
}
private void mergeSort(int left, int right, int[] nums) {
// 区间内只有一个元素或者元素不存在, 那么直接返回没有排序的必要
if(left >= right) return;
// 归并排序的主逻辑过程
// 1. 找到一个中间位置
int mid = (left + right) / 2;
// [left, mid] [mid + 1, right] 划分为两个区间
// 2. 先进行左右两边的分割,排个序。相信这两个函数能完成左右区间的排序
// (递归不用太关注于具体的展开过程)
mergeSort(left, mid, nums);
mergeSort(mid + 1, right, nums);
// 3. 两边排好序之后, 合并有序数组。(核心操作)
// cur1 遍历 [left, mid] 这个区间
// cur2 遍历 [mid + 1, right] 这个区间
// i 遍历 tmp 辅助数组
int cur1 = left, cur2 = mid + 1, i = 0;
// while(cur1 <= left && cur2 <= right) {
while(cur1 <= mid && cur2 <= right) {
tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
}
// 4.处理cur1 或者 cur2 还没有遍历完的数组
while(cur1 <= mid) tmp[i++] = nums[cur1++];
while(cur2 <= right) tmp[i++] = nums[cur2++];
// 5. 把辅助数组中的数组拷贝到原数组中
// j 遍历的是原数组, nums中的 【left, right】 这个区间
for (int j = left; j <= right; j++) {
// tmp 要从 0 开始遍历
nums[j] = tmp[j - left];
}
}
用到了一个全局的辅助数组,而不是每次进入递归都要重新new一下,这样写起来会方便一点。
🎗️🎗️🎗️ 好啦,到这里有关本题的分享就没了,如果感觉做的还不错的话可以点个赞,关注一下,你的支持就是我继续下去的动力,我们下期再见,拜了个拜~ ☆*: .。. o(≧▽≦)o .。.:*☆