37-咸鱼学Java-归并排序

简介

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 —–百度百科
这里写图片描述
先红色的归并,再蓝色的,再紫色

代码

/**
     * 归并函数
     * @param array 数组
     */
    public static void mergeSort(int[] array)
    {
        //每次每份的过程1   2    4  8  16  -------小于array.length
        for (int i = 1; i < array.length; i= i *2) {
            //根据份数归并排序
            merge(array,i);
        }
    }
    /**
     * 归并
     * @param array 数组
     * @param i     每一个归并段的数据个数
     */
    private static void merge(int[] array, int i) {
        //指引变量
        int s1,e1,s2,e2;
        //指向第一份的头
        s1 = 0;
        //执向第二份的头
        s2 = s1+i;
        //指向第一份的尾
        e1 = s1+i-1;
        //指向第二份的尾,因为有可能第二份不完全,所以要进行判别
        //如果s2本来的位置大于array.length
        //所以当越界的时候需要将其拉回到数组的最后一个下标处
        e2 = s2+i-1 > (array.length-1) ? array.length-1 : s2+i-1;
        //一个临时数组用来放已经归并完成的数组段
        int [] tempArr = new int[array.length];
        //tempArr的下标
        int temp = 0;
        //循环直到第二份的头超越array.length及s2循环到整个数组最后
        while(s2 < array.length)
        {
            //循环直到一份全部合并结束
            while(s1<=e1&&s2<=e2)
            {
                //如果s1位置的比s2大,插入最小的s2
                if(array[s1]>array[s2])
                {
                    tempArr[temp++] = array[s2++];
                }
                //反之亦然
                else{
                    tempArr[temp++] = array[s1++];
                }
            }
            //因为有可能某个部分没全部插入,此处需要将剩下的补充进去
            //当s1没合并完的时候
            while(s1<=e1)
            {
                //将剩余的放进去
                tempArr[temp++] = array[s1++];
            }
            //同上等s2没合并完的时候
            while(s2<=e2)
            {
                tempArr[temp++] = array[s2++];
            }
            //重新设置s1 s2 e1 e2的指向下标
            s1 = e2+1;
            s2 = s1+i;
            e1 = s1+i-1;
            e2 = s2+i-1>(array.length-1)?array.length-1:s2+i-1;
        }
        //剩下的s1 --- e1直接的数
        while(s1<array.length)
        {
            tempArr[temp++] = array[s1++];
        }
        //将临时数组的数放回到原数组
        for (int j = 0; j <array.length; j++) {
            array[j] = tempArr[j];
        }
    }

测试

public static void main(String[] args) {
        int[] a = {3,43,546,76,34,13,673,31};
        System.out.println("原数组为:"+Arrays.toString(a));
        System.out.println();
        mergeSort(a);
        System.out.println(Arrays.toString(a));
    }

结果
原数组为:[3, 43, 546, 76, 34, 13, 673, 31]
[3, 13, 31, 34, 43, 76, 546, 673]

逐步分析

第一次合并
i=2这里写图片描述
第二次合并
i=4
这里写图片描述
第三次合并
i=8
这里写图片描述
相当于每次只合并于一段,使得一段有序。

合并的过程

以i=4为例子
这里写图片描述
设置指引下标
这里写图片描述
比较s1,s2根据不同情况进行移动直到某一个存放完毕
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
s1超越e1
s2未合并完,将s2剩余的合并回去
这里写图片描述
完成合并

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值