vlambda博客
学习文章列表

【图解算法】归并排序

✊不积跬步,无以至千里;不积小流,无以成江海。



木偶人 mouu

读完需要

5
分钟

速读仅需 3 分钟


思路

1.将n个元素分成两个含n/2元素的子序列(左边可能比右边多1个数),直到拆分的每个数组只包含一个元素。

2.从最底层开始逐步合并两个排好序的数列。

【图解算法】归并排序

图解

归并排序

算法分析


复杂度分析

归并排序算法每次将序列折半分组,共需要logn轮,因此归并排序算法的时间复杂度是O(nlogn)。不管是有序还是无序都需要拆分数组,进行前后比较,所以最好和最坏时间复杂度是一样的都是O(nlogn)。


合并数组需要放在新的数组中,借助额外的空间,所以空间复杂度是O(n)。


稳定性分析

因为拆分数组是按照对半拆分,元素前后顺序没有改变,排序也是从前到后,对比前后顺序也是没变,所以稳定

查看下方链接,在bilibili哔哩哔哩观看
https://www.bilibili.com/video/BV1mS4y1r7Jg/

代码

public static void mergeSort(int[] arr, int first, int last){
    if(null == arr || arr.length < 0 || first == last){
        return;
    }
    mergeSort(arr, first, (last + first)/2);
    mergeSort(arr, (last + first)/2 + 1, last);
    sort(arr, first, (last + first)/2, last);

}

//这个方法是合并两个有序数组,就好像直接插入排序算法一样
public static void sort(int[] arr, int first, int mid, int last ){
    int[] temp = new int[last - first + 1];
    int i = 0;
    int j = 0;
    int index = 0;
    while(i < mid - first + 1 && j < last - mid){
        if(arr[first + i] >= arr[mid + 1 + j]){
            temp[index] = arr[mid + 1 + j];
            j++;
            index++;
        } else {
            temp[index] = arr[first + i];
            i++;
            index++;
        }
    }
    while(i < mid - first + 1){
        temp[index] = arr[first + i];
        index++;
        i++;
    }
    while(j < last - mid){
        temp[index] = arr[mid + 1 + j];
        index++;
        j++;
    }
    for(int k = first, n = 0; k <= last; k++, n++){
        arr[k] = temp[n];
    }

}

public static void main(String[] args) {
    int[] arr=new int[]{123,45,6,22,99,1,38,41,-6,0};
    //归并排序
    mergeSort(arr,0,9);

    System.out.println("归并排序后的结果是:");
    System.out.println(Arrays.toString(arr));
}

总结

时间复杂度

  • 最小时间复杂度是O(nlogn)

  • 最大时间复杂度是O(nlogn)

  • 平均时间复杂度是O(nlogn)


空间复杂度

  • O(n)


稳定性分析度

  • 稳定