八大排序之归并排序(建议与快排一起看)

排序算法

冒泡排序

简单选择排序

直接插入排序

希尔(shell)排序

快速排序

归并排序

归并排序

排序原理:

  1. 尽可能的将一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
  2. 将相邻的两个子组进行合并成一个有序的大组;
  3. 不断的重复步骤2,直到最终只有一个组为止。

在这里插入图片描述
对最后合并细化分析,核心代码Merge
在这里插入图片描述

Java代码

import java.util.Arrays;
public class MergeSort {
    
    

    private static int[] arr;
    public static void sort(int[] a){
    
    
        arr = new int[a.length];
        sort(a,0,a.length-1);
    }

    private static void sort(int[] a,int lo, int hi){
    
    
        if(lo>=hi) return;
        int mid = lo + (hi - lo)/2;
        sort(a,lo,mid);
        sort(a,mid+1,hi);
        //合并两个数组
        merge(a,lo,mid,hi);
    }
    private static void merge(int[] a, int lo,int mid ,int hi ){
    
    
        //指向辅助数组的指针。
        int i = lo;
        //定义第一个数组的指针,初始指向第一个元素;
        int p1 = lo;
        //定义第二个数组的指针,初始指向第一个元素
        int p2 = mid+1;

        //比较两个数组指针指向的元素的大小,哪个小,就放入arr数组
        while(p1<=mid&&p2<=hi){
    
    
            if(a[p1]<a[p2]){
    
    
                arr[i++]=a[p1++];
            }else{
    
    
                arr[i++]=a[p2++];
            }
        }
        //如果数组二遍历完,数组一没完
        while(p1<=mid){
    
    
            arr[i++] = a[p1++];
        }
        //如果数组一遍历完,数组二没完
        while(p2<=hi){
    
    
            arr[i++] = a[p2++];
        }

        //拷贝数组
        for (int i1 = lo; i1 <= hi; i1++) {
    
    
            a[i1] = arr[i1];
        }

    }

    public static void main(String[] args) {
    
    
        int[] a = {
    
    8, 4, 5, 7, 1, 3, 6, 2};
        sort(a);
        System.out.println(Arrays.toString(a));
    }

}

算法复杂度分析

O(nlogn)

归并排序是分治思想的最典型的例子,上面的算法中,对a[lo…hi]进行排序,先将它分为a[lo…mid]和a[mid+1…hi]
两部分,分别通过递归调用将他们单独排序,最后将有序的子数组归并为最终的排序结果。该递归的出口在于如果
一个数组不能再被分为两个子数组,那么就会执行merge进行归并,在归并的时候判断元素的大小进行排序。
在这里插入图片描述
用树状图来描述归并,如果一个数组有8个元素,那么它将每次除以2找最小的子数组,共拆log8次,值为3,所以树共有3层,那么自顶向下第k层有2^k个子数组,每个数组的长度为2^(3-k),归并最多需要2^(3-k)次比较。因此每层的比较次数为 2^k * 2^(3-k)=2^3,那么3层总共为 3*2^3。

假设元素的个数为n,那么使用归并排序拆分的次数为log2(n),所以共log2(n)层,那么使用log2(n)替换上面32^3中 的3这个层数,最终得出的归并排序的时间复杂度为:log2(n) 2^(log2(n))=log2(n)*n,根据大O推导法则,忽略底数,最终归并排序的时间复杂度为O(nlogn).

扫描二维码关注公众号,回复: 11841847 查看本文章

归并排序需要申请额外的数组空间,导致空间复杂度提升,是典型的以空间换时间的操作。

稳定性

稳定的

归并排序在归并的过程中,只有arr[i]<arr[i+1]的时候才会交换位置,如果两个元素相等则不会交换位置,所以它
并不会破坏稳定性,归并排序是稳定的。

猜你喜欢

转载自blog.csdn.net/ren9436/article/details/108901837
今日推荐