归并排序 java实现

83 阅读4分钟

写这篇文章的时候 我对归并排序的理解没那么深 想了想还是写下这篇文章 算法很重要 但是出现问题如何解决 如何减少错误的发生 当然多多理解算法好处 在这篇文章我主要写了一下 在我平时写代码的时候两个细节吧 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 也就是说 如果输入是一个 正三角 输出的有点像倒三角 所以如果递归它是不会直接执行下面的代码 方便了我们实现 拆分和合并

参考链接juejin.cn/post/716146…

 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

批注 2023-05-18 221955.png

第二部分 如何合并数组 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 当 运行到此处时满足条件才会断住

image.png 然后我们点击debug

image.png 我们现在知道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…

最后本人水平有限 文章难免出现错误 敬请指出 希望我们一同成长