【Data Structure/Algorithm】排序之归并排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk1134314305/article/details/78216690

本文针对《Algorithms》Fourth Edition书中的归并排序做一个总结,当做学习笔记以作记录。

1,归并排序的算法原理

归并排序算法的步骤为:

1)将数组逐步拆分成两个子数组,直至每个数组的大小为1。
(2)因为分割到最后,数组的大小为1,因此,这个时候,就相当于数组已经排序
(3)对数组进行两两合并排序,首先是合并数组大小为1的子数组,合并完之后数组大小为2,然后继续合并排序,得到大小为4的数组。这样逐层进行下去,得到了最终的大小为N的数组(即排序完毕)。

这里写图片描述

上面是对归并排序算法的一个综述。图中描述了归并排序算法的关键步骤。归并排序算法的关键步

(1)将数组分为两个子数组
(2)分别对两个子数组进行排序
(3)对两个数组进行合并,得到了最终的排序数组

对于已经排序好的两个子数组怎么进行合并,合并成一个有序的数组呢?

下面的图片很好的解释了这个过程:

这里写图片描述

上面的数组的排序过程就是利用了两个指针,i和j,分别指向左边的子数组和右边的子数组。i,j初始的时候都指向各个数组的第一个元素。如果谁指向的那个元素比较小,那就将这个元素放进新数组。如果i或者j一直移动到了自己所指向数组的最后一个元素,那么就将另一个指针指向的数组的剩余没有遍历的数组放进新数组。

下面用图例来说明这一过程:

这里写图片描述
这里写图片描述

这样就得到了一个有序的大数组。

另外,可以通过动画查看,归并排序算法的过程

归并排序动画展示

2,归并排序的两种类型

归并排序有两种算法,自顶向下和自底向上。

2.1 自顶向下归并排序

排序算法如下图所示

这里写图片描述

这种算法是从顶部开始,向下迭代分隔合并进行的。

2.2自底向上的排序算法

这里写图片描述

这种算法是从底部最小大小(最小大小为1的数组)的数组进行合并排序,逐层向上排序进行的。

3,代码

package sort;

public class MergeSort {
    public static void main(String[] args) {
        int[] arr={9,6,4,0};
//      sort(arr, 0, arr.length-1);
        sort(arr);
        printarr(arr);
    }
    /**
     * 1,自顶向下归并排序
     * @param arr   要排序的数组
     */
    public static void sort(int[] arr,int lo,int hi){
        if(hi<=lo) return;
        int mid=(lo+hi)/2;
        sort(arr, lo, mid);
        sort(arr, mid+1, hi);
        merge(arr,lo,mid,hi);
        printarr(arr);
    }
    /**
     * 下面的方法是对已经排序好的两个子序列进行归并、排序操作,得到一个从小到大的序列
     * @param arr
     * @param lo
     * @param mid
     * @param hi
     */
    public static void merge(int[] arr,int lo,int mid,int hi){
        int[] arr_new=new int[arr.length];
        for(int i=lo;i<=hi;i++){
            arr_new[i]=arr[i];
        }
        int i=lo;
        int j=mid+1;
        for(int k=lo;k<=hi;k++){
            if(i>mid)   arr[k]=arr_new[j++];
            else if(j>hi)   arr[k]=arr_new[i++];
            else if(arr_new[i]>arr_new[j])  arr[k]=arr_new[j++];
            else    arr[k]=arr_new[i++];
        }
    }
    /**
     * 2,自底向上归并排序
     * @param arr
     */
    public static void sort(int[] arr){
        int N=arr.length;
        for(int arr_size=1;arr_size<N;arr_size=2*arr_size){
            for(int lo=0;lo<N-arr_size;lo+=arr_size*2){
                merge(arr,lo,lo+arr_size-1,Math.min(lo+2*arr_size-1, N-1));
            }
        }
    }

    public static void printarr(int[] arr){
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]);
            System.out.print(" ");
        }
        System.out.println();
    }

}

4,时间复杂度

时间复杂度为O(Nlog(N)),关于时间复杂度的证明,可以参考《Algorithms》Fourth Edition中的证明,这部分不在本文的范围内。同时需要注意的是:
归并排序算法的一个缺点就是:
需要一个临时数组来复制原数组的值,因此空间复杂度为O(N)。

猜你喜欢

转载自blog.csdn.net/wk1134314305/article/details/78216690
今日推荐