归并排序

基本思想

是利用归并的思想进行排序的放法,它的原理是假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到 n/2 个长度为2或者1的有序子序列,然后在两两归并,直到得到一个长度为n的有序序列为止。

排序方法平均情况最好情况最坏情况辅助空间稳定性
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定



待排序的记录序列中可能存在两个或两个以上关键字相等的记录。排序前的序列中 Ri 领先于 Rj ,即 i<j ,若在排序后的序列中 Ri 仍然领先于 Ri ,则称所用的方法是稳定的。
稳定的排序有:插入排序基数排序归并排序冒泡排序计数排序
不稳定的排序有:快速排序希尔排序简单选择排序堆排序

代码实现

public static void sort(int[] data, int left, int right) {   
    if(left<right){  
        //找出中间索引  
        int center=(left+right)/2;  
        //对左边数组进行递归  
        sort(data,left,center);  
        //对右边数组进行递归  
        sort(data,center+1,right);  
        //合并  
        merge(data,left,center,right);         
    }  
} 
public static void merge(int[] data, int left, int center, int right) {    
    int[] tmpArr=new int[data.length];  
    int mid=center+1;  
    //third记录中间数组的索引  
    int third=left;  
    int tmp=left;  
    while(left<=center&&mid<=right){  
        //从两个数组中取出最小的放入中间数组  
        if(data[left]<=data[mid]){  
            tmpArr[third++]=data[left++];  
        }else{  
            tmpArr[third++]=data[mid++];  
        }  
    }  
    //剩余部分依次放入中间数组  
    while(mid<=right){  
        tmpArr[third++]=data[mid++];  
    }  
    while(left<=center){  
        tmpArr[third++]=data[left++];  
    }  
    //将中间数组中的内容复制回原数组  
    while(tmp<=right){  
        data[tmp]=tmpArr[tmp++];  
    }   
}  

数据交换示意图

这里写图片描述

代码优化

上文的代码使用递归的方式,尽管代码清晰而且比较容易理解,但是将会消耗大量的时间和空间,下面实现一下非递归的版本,这应该是自底向上的归并。一开始的归并长度为1,以后每次加倍,归并的时候要注意处理归并段的长度为奇数和的情况和最后一个归并段的长度和前面的不等的情况,需要做一下处理。

    public static void sortNo(int[] A){
        int len = 1;
        int low = 0;
        int mid;
        int high;
        // 程序边界的处理非常重要
        while (len <= A.length) {
            for (int i = 0; i + len <= A.length - 1; i += len * 2) {
           System.out.println("i="+i);
           System.out.println("len="+len);
                low = i;
                mid = i + len - 1;
                high = i + len * 2 - 1;
        //最后一个为奇数的情况
                if (high > A.length - 1)
                    high = A.length - 1;
                merge(A, i, mid, high);
                System.out.println(Arrays.toString(A));
            }
        //长度加倍
            len += len;
        }
    }

以{50,10,90,30,70,40,80,60,20}为例
这里写图片描述
参考资料
[1] 大话数据结构 清华大学出版社 程杰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值