归并排序(java递归实现)

本文详细解释了归并排序算法的工作原理,利用分治法和双指针技巧,通过实例展示了如何将数列打散并逐步合并,强调了双指针在比较和合并过程中的关键作用。
摘要由CSDN通过智能技术生成

归并排序是稳定排序,它也是一种十分高效的排序,它也是timesort算法的基础,归并排序算法使用到了分治法(教材上一直都这么说,但这属于是一句正确的废话),当然,具体实现的过程中也用到了双指针的思想。网上大部分的教程啰里吧嗦讲了好几页,这里废话不多说,直接说原理:

第一步:把数列中的所有数字“打散”,

第二步:用双指针的思路,再把散掉的数字重新组合在一起。

即先“分”,再“治”(归并)。

现在将5,4,3,6,1,2从小到大排序,上图!!!

首先实现第一步,将数列分成左右两个部分,将数列“打散”,但是“打散”要有一定的套路,逐层从中间分开,最后将所有数字拆出来(棕色圆圈代表索引值)

开始第二步,把散掉的数字组合起来,如图:

通过图我们看到了,打散和合并的过程是对称的,怎么打散的,后来就再怎么合并,只不过在合并的过程中,有一个大小比较的过程,现在的关键问题是:怎么比较?比较后又怎么合并?

这就需要借助到两个工具——双指针和临时数组!

这里以6、1、2这三个数字的合并过程为例。

先创建一个长度为2的临时数组,由于6和1最开始是在一起的,所以我们现在再把它们合并到一起。由于6大于1,所以把它们两个放到一个临时数组中[1,6],然后再创建一个长度为3的临时数组,开始合并[1,6]和[2],那么我们该如何把数字放到这个临时数组的合适位置呢?此时可以借助双指针!一个指针指向1,另一个指针指向2,2比1大,所以把1放到临时数组的第一个位置。

 1被取走了,所以现在把黑色指针指到6,红色指针不变。

2比6小,所以把2放到临时数组的第二个位置。还剩一个6,所以把6放到临时数组第3个位置。因此右半部分的数字排序完毕!

 我们依然按照相同的思路将5,4,3合并成有序数列:

最后的步骤就是先创建一个长度为6的空数组arr,然后用双指针,分别指向[3,4,5]和[1,2,6]这两个数列中的第一个字,把下面这两个有序数列中的数字放到这个长度为6的空数组里:

  • 3大于1,所以在arr[0]的位置写入1,黑色指针不动,红色指针向右移动一位。

  • 3大于2,所以在arr[1]的位置写入2,黑色指针不动,红色指针向右移动一位。 

  •  6大于3,所以在arr[2]的位置写入3,黑色指针向右移动一位,红色指针不动。

  •  6大于4,所以在arr[3]的位置写入4,黑色指针向右移动一位,红色指针不动。 

  •  6大于5,所以在arr[4]的位置写入5,至此,左侧的数字全部“归位”,而右侧剩余的数字(6)直接按顺序放入arr中即可。所有数字排序完毕。

如果一侧的数字全部放入空数组以后,另一侧的数字还有剩余,那么这些数字不用再进行比较,直接按顺序放进空数组即可。 

 废话不多说!上代码!

    // 测试代码
    public static void main(String[] args) {
        // 测试数组
        int[] arr = {4, 3, 2, 0, 7, 41, 6, 5, 3};
        // 成功排序后的数组
        int[] A = mergeSort(arr, 0, arr.length - 1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(A[i]);
        }
    }

    // 归并排序代码
    public static int[] mergeSort(int[] arr, int left, int right) {
        // 分割到只剩一个数字时,将这个数字放进数组并返回
        if (left == right) {
            return new int[]{arr[left]};
        }
        int mid = (left + right) / 2;
        int[] Larr = mergeSort(arr, left, mid);
        int[] Rarr = mergeSort(arr, mid + 1, right);
        int[] temp = new int[Larr.length + Rarr.length];
        int i = 0;
        int j = 0;
        int k = 0;
        while (i < Larr.length && j < Rarr.length) {
            if (Larr[i] >= Rarr[j]) {
                temp[k++] = Rarr[j++];
            } else {
                temp[k++] = Larr[i++];
            }
        }
        // 下面两个while循环,是将左右两个数组中的剩余数字全部放进临时数组temp中
        while (i < Larr.length) {
            temp[k++] = Larr[i++];
        }
        while (j < Rarr.length) {
            temp[k++] = Rarr[j++];
        }
        return temp;
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值