写这篇文章的时候 我对归并排序的理解没那么深 想了想还是写下这篇文章 算法很重要 但是出现问题如何解决 如何减少错误的发生 当然多多理解算法好处 在这篇文章我主要写了一下 在我平时写代码的时候两个细节吧 1. 测试 2.结果不对如何处理
那现在我来描述一下如何实现
实现过程
1 对数组进行拆分 直到数组长度为1 2 对长度为1的数组进行合并 逐渐合并成原数组
第一部分 如何实现 在那之前我想聊一聊下面这段代码的结果 也就是递归的实现
public static void sIn(int n){
if (n >= 0){
sIn(n-1);
System.out.println(n-1);
System.out.println("A");
}
}
public static void main(String[] args) {
sIn(2); // -1 A 0 A 1 A
}
在这里递归会如何执行? 首先执行到第一个sin(n-1) 代码会 进入sin(1) 并再次进入 sin(0) 然后才是打印 n - 1 也就是 -1 再打印 A 打印 0 A 打印 1 A 也就是说 如果输入是一个 正三角 输出的有点像倒三角 所以如果递归它是不会直接执行下面的代码 方便了我们实现 拆分和合并
public void mergeSort(int[] nums, int start, int end) { //第1行
int mid = (start + end) / 2; //第2行
if (start == end) {//第3行
return;//第4行
} else {//第5行
if (start < mid)//第6行
mergeSort(nums, start, mid);//第7行
if (mid + 1 < end)//第8行 // 相当于 奇数时 把数组分为前奇数后偶数 长度3的数组 分为 1 2 把中间值放到后面的数组里
mergeSort(nums, mid, end);//第9行
sort(nums, start, mid, end);//第10行
}
}
这里的代码我们先讨论递归部分首先如果它遇到 mergeSort 它会进去 下面的代码不会执行 并且数组长度被"切一半"(没切用mid表示中间部分) 代码一直执行直到没有mergesort 开始执行sort
第二部分 如何合并数组 leetcode #### 88. 合并两个有序数组
想法就是双指针(默认从小到大排序)
左指针 右指针 循环直到有一个数组到结尾了
如果左指针的值小于右指针的值 左指针++
如果右指针的值大于左指针 两边值交换并且右指针++
如果两个数组有一个没有遍历完
在我们这里左边长度小于右边 会出现 4 5 6 1 2 变成 1 2 6 4 5 此时 r == end l = start
package project.untit;
import java.util.Arrays;
import java.util.Objects;
public class MergeSort {
public void mergeSort(int[] nums) {
int start = 0, end = nums.length - 1;
mergeSort(nums, start, end);
}
public void mergeSort(int[] nums, int start, int end) {
int mid = (start + end) / 2;
if (start == end) {
return;
} else { //0 1 2 3 4 5
if (start < mid)
mergeSort(nums, start, mid);
// 相当于 奇数时 把数组分为前奇数后偶数 长度3的数组 分为 1 2 把中间值放到后面的数组里
if (mid + 1 < end)
mergeSort(nums, mid, end);
sort(nums, start, mid, end);
}
}
public void sort(int[] nums, int start, int mid, int end) {
int l = start, r = mid;
while (l <= mid && r < end) {
if (nums[l] < nums[r]) {
l++;
//if (nums[l]>nums[r])
} else {
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
r++;
}
}
System.out.println();
// 4 5 6 1 2
if (r == end && mid == l) {
for (int index = mid; index < end; index++) {
if (!(nums[index] <= nums[index + 1])) {
int temp = nums[index];
nums[index] = nums[index + 1];
nums[index + 1] = temp;
}
}
}
System.out.println();
}
// 1 2 6 4 5
public static void test(int[] nums, int l, int mid, int end) {
if (l < mid)
for (int index = mid; index < end; index++) {
if (!(nums[index] <= nums[index + 1])) {
int temp = nums[index];
nums[index] = nums[index + 1];
nums[index + 1] = temp;
}
}
for (int anInt : nums) {
System.out.println(anInt);
}
}
//1 2 6 4 5 ==> 1 2 4 6 5
public static void test01(int[] nums, int r, int end) {
if (r < end) {
while (r < end) {
//数组越界
if (nums[r] > nums[r + 1]) {
int temp = nums[r];
nums[r] = nums[r + 1];
nums[r + 1] = temp;
}
r++;
}
}
for (int anInt : nums) {
System.out.println(anInt);
}
}
public static void main(String[] args) {
MergeSort mergeSort = new MergeSort();
int[] ints = {1, 6, 5, 2, 4};
mergeSort.mergeSort(ints);
for (int anInt : ints) {
System.out.println(anInt);
}
// test(new int[]{1, 2, 6, 4, 5}, 0, 2,4);
// test01(new int[]{1, 2, 4, 6, 5}, 3, 4);
}
}
测试
一般情况下 写完之后我们并不知道代码有没有错误 我的建议是 很可能出错的代码提取出来先跑一下 比如这题的左边数组长于右边数组和右边数组长于左边数组 你可以写一个方法 找一个测试案例 我们知道 比如在这里测试案例就是数组是 [1,2,6,4,5]时l = 0 mid = 2 end = 4 写如下测试
public static void test(int[] nums, int l, int mid, int end) {
if (l < mid)
for (int index = mid; index < end; index++) {
if (!(nums[index] <= nums[index + 1])) {
int temp = nums[index];
nums[index] = nums[index + 1];
nums[index + 1] = temp;
}
}
for (int anInt : nums) {
System.out.println(anInt);
}
}
public static void main(String[] args) {
test(new int[]{1, 2, 6, 4, 5}, 0, 2,4);
}
结果不对如何处理
比如在这里我第一次 int[] ints = {1, 6, 5, 2, 4}; run出来结果是[1,2,4,6,5] 这时候我们找个地方 比如最后sort方法最后加一个 System.out.println(); 并且下条件断点Arrays.equals(nums, new int[]{1, 2, 4, 6, 5}) ------条件断点指idea 断点上面右键点击condition 当 运行到此处时满足条件才会断住
然后我们点击debug
我们现在知道start == 0 mid == 2 end == 4.
在这里要才一下else if(r<end)没进去 进去结果应该就是对的.
接下来我们在偏上面的地方条件断点 condition =》start == 0 && mid == 2 && end == 4.
这里我们在最上面的while循环里面试一下两个断点 (start == 0 && mid == 2 && end == 4) || Arrays.equals(nums, new int[]{1, 2, 4, 6, 5}) 发现满足第一个条件 不满足 第二个断点说明数组变化了 懒一点的像我 多加一个if 问题解决了
if (r == end && mid == l) {
for (int index = mid; index < end; index++) {
if (!(nums[index] <= nums[index + 1])) {
int temp = nums[index];
nums[index] = nums[index + 1];
nums[index + 1] = temp;
}
}
}
当然那个else if (r < end) 肯定有错误但是为了不影响功能我们 加上了多加那个if
错误的代码 评论区给出
在这里我说一句代码大概率有问题目前三个测试都通过了 // 1 2 6 4 5 2,5,4,9,6
参考链接 www.bilibili.com/video/BV1nP…
最后本人水平有限 文章难免出现错误 敬请指出 希望我们一同成长