走进数据结构之排序(七)---归并排序

本文详细介绍了归并排序的算法原理,通过一个形象的老师排队例子来辅助理解,提供了完整的Java代码实现,并分析了归并排序的时间复杂度为O(n*log2(n))和空间复杂度为O(n),同时强调了该算法的稳定性。
摘要由CSDN通过智能技术生成

一、归并排序算法分析

将n个元素的数据序列看成是由n个长度为1的排序子序列组成,反复将相邻的两个子序列归并成一个排序子序列,直到合并成一个序列,则排序完成。

二、代码实现

package top.einino.mergesort;

public class MergeSort {

//将X中分别以begin1, begin2开始的两个相邻子序列归并(升序)到Y中, 子序列长度为n
    private static void merge(int[] X, int[] Y, int begin1, int begin2, int n){
        int i = begin1, j = begin2, k = begin1;
        //将X中两个相邻子序列归并到Y中
        while(i<begin1+n && j<begin2+n && j<X.length){
            //升序将较小值复制到Y中
            if(X[i]<X[j]){
                Y[k++] = X[i++];
            }else{
                Y[k++] = X[j++];
            }
        }
        //将前一个子序列剩余元素复制到Y,序列长度可能不足n
        while(i<begin1+n && i<X.length){
            Y[k++] = X[i++];
        }
        //将后一个子序列剩余元素复制到Y中
        while(j<begin2+n && j<X.length){
            Y[k++] = X[j++];
        }
    }
//一趟归并,将X中若干相邻子序列两两归并到Y中,子序列长度为n
 private static void mergepass(int[] X, int[] Y, int n){
        System.out.println("子序列长度n="+ n + " ");
        for(int i=0; i<X.length; i+=2*n){
            merge(X, Y, i, i+n, n);
        }
        print(Y);
    }
 //归并排序(升序)
    private static void mergeSort(int[] X){
        //Y数组长度同X数组
        int[] Y = new int[X.length];
        //排序子序列长度,初值为1
        int n = 1;
        while(n<X.length){
            //一趟归并,将X中若干邻子序列归并到Y
            mergepass(X, Y, n);
            //子序列长度加倍
            n*=2;
            if(n<X.length){
                //一趟归并,将Y中若干相邻子序列再归并到X
                mergepass(Y, X, n);
                n*=2;
            }
        }
    }
//输出排序数组
private static void print(int[] keys) {
for(int key : keys){
System.out.print(key+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] X = {97, 82, 75, 53, 17, 61, 70, 12, 61, 58, 26};
mergeSort(X);
}
}

三、形象的小例子

老师又来排队了!

初始队列:A学生197,B学生182,C学生175,D学生153,E学生117,F学生161,G学生170,H学生112,I学生161,J学生158,K学生126

老师开始第一趟排序

首先老师对所有学生进行相邻距离为1的学生分为一组,并且比较的是每组的前1位与后1位进行比较,分组情况如下:

第一组:A、B

第二组:C、D

第三组:E、F

第四组:G、H

第五组:I、J

第六组:K

进行第一组的排序,结果A>B、所以先将B拉出队伍排到第一位,再将剩下不用再进行排序的A拉出队伍排到B后面

进行第二组的排序,结果C>D,所以先将D拉出队伍排到A学生的后面,再将C学生排到D学生的后面

同理,对其他组进行排序:最后结果为

B学生182,A学生197,D学生153,C学生175,E学生117,F学生161,H学生112,G学生170,J学生158,I学生161,K学生126

老师进行第二趟排序,将上一趟排序的结果再进行分组相邻距离为2的分为一组,并且比较的是每组的前2位与后两位进行比较,分组情况如下:

第一组:B、A    \  D、C

第二组:E、F     \  H、G

第三组:J、I \ K

老师开始进行第一组排序,

首先进行B与D的比较,结果D<B,所以先将D学生拉出队伍,排到第一位,再将C与B进行比较,结果C<B,再把C拉出队伍,排到D的后面,然后依次把B、A排到C的后面

再进行第二组的排序

首先进行E与H的比较,结果E>H,所以行将H排到A学生的后面,再进行E与G的比较,结果E<G,再把E排到H的后面,再将F与G进行比较,结果F<G,所以把F排到E的后面,G依次排到F的后面

同理进行第三组的排序,结果为K、J、I

第二趟 排序的最后结果是D学生153,C学生175B学生182,A学生197,H学生112,E学生117,F学生161,G学生170,K学生126,J学生158,I学生161

老师进行第三趟的排序

首先进行分组,以相邻距离为4的分为一组,并且比较的是每组前4位与后4位的比较,分组情况如下:

第一组:D、C、B、A\H、E、F、G

第二组:K、J、I

进行第一组的排序,

进行D与H的比较,结果D>H,所以先将H拉出队伍排到第一个,再进行D与E的比较,结果D>E,将E排到H的后面,再进行D与F的比较,结果D<F,所以将D排到E的后面,再进行F与C的比较,结果F<C,所以把F排到D的后面,再进行C与G的比较,结果C>G,所以将G排到F的后面,因为没得进行比较了,所以依次把C、B、A排到G的后面

再进行第二组的排序,因为第一组只有3个人,还不到4个人,就无需进行比较了

所以第三趟排序结果为:H学生112,E学生117,D学生153,F学生161,G学生170,C学生175,B学生182,A学生197,K学生126,J学生158,I学生161

老师进行第四趟的排序

首先进行分组,以相邻距离为8的分为一组,并且比较的是每组前8位与后8位的比较,分组情况如下:

第一组:H、E、D、F、G、C、B、A\K、J、I

老师进行第一组的排序,也是唯一一组,首先进行H与K的比较,结果H<K,所以先把H拉出队伍,排到第一位,再进行E与K的比较,结果E<K,把E排到H的后面,再进行D与K的比较,结果D>K,所以把K排到E的后面,再进行D与J的比较,结果D<J,所以把D排到K的后面,再进行比较F与J,结果F>J,所以把J排到D的后面,再进行F与I的比较,结果F=I,所以把F排到J的后面,再进行I与G的比较,结果G>I,所以把I排到F的后面,然后因为没得比较,所以依次把G、C、B、A排到I的后面,

最后的排序结果为:H学生112,E学生117,K学生126,D学生153,J学生158,F学生161,I学生161,G学生170,C学生175,B学生182,A学生197,

四、归并排序的时间复杂度

n个元素归并排序,每趟比较n-1次,数据移动n-1次,进行log2(n)趟,时间复杂度为O(n*log2(n))

五、归并排序的空间复杂度

归并排序需要O(n)容量的附加空间,与数据序列的存储容量相等,空间复杂度为O(n)

六、稳定性

在归并排序算法中,关键字相等的元素会相遇进行比较,算法不改变它们的原有次序,所以,归并排序算法是稳定的

七、小结

本博文从归并排序算法分析,升序代码实现,老师排队的例子讲演,时间复杂度,空间复杂度以及稳定性介绍了归并排序的方方面面。

如果有疑问或者对该博文有何看法或建议或有问题的,欢迎评论,恳请指正!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值