图解十大排序四---归并排序

94 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

图解十大排序

4.1 前文回顾

在上篇文章中给大家介绍了第一种时间复杂度为 O(nlog2 n)的排序方法,那么今日就让我们来学习第二种,在介绍之前,大家还记得选择排序嘛,和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。

4.2 归并排序

归并排序 是建立在归并操作上的一种有效的排序算法。该算法是采用分治的思想。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并

官方回答看不懂?没关系,总结来说就是: 通过将当前乱序数组分成长度近似的两份,分别进行 递归  调用,然后再对这两个排好序的数组,利用两个指针,将数据元素依次比较,选择相对较小的元素存到一个 辅助数组 中,再将 辅助数组 中的数据存回 原数组 。

让我们来看一个例子 给定无序数组 : [3, 5, 2, 6, 4, 8, 7, 9]

比特截图2022-06-02-21-40-05.png

  1. 将数组中的元素进行对半分组,第1层分成2个大组,每组n/2个元素; 第2层分成4个小组,每组n/4个元素; 第3层分成8个更小的组,每组n/8个元素; …… 一直到每组只有一个元素。

比特截图2022-06-02-21-42-48.png

比特截图2022-06-02-21-44-48.png

比特截图2022-06-02-21-46-04.png

  1. 当每个小组内部比较出先后顺序以后,小组之间会展开进一 步的比较和排序,合并成一个大组;大组之间继续比较和排序,再合 并成更大的组……最终,所有元素合并成了一个有序的集合。这就是归并

比特截图2022-06-02-21-46-04.png

比特截图2022-06-02-21-44-48.png

比特截图2022-06-02-21-54-25.png

比特截图2022-06-02-21-55-38.png

那我们如何将把两个有序的小集合,归并成一个有序的大集合呢?

第一轮 :额外创建一个数组,用来存储俩个小数组排序之后的结果,数组长度当然就是俩个小数组之和啦 (p1,p2,p是三个辅助指针,用于记录当前操作的位 置。)

比特截图2022-06-02-22-08-42.png

第二轮 : 从左到右依次比较俩数组中的元素,把较小的放入大集合中

  • 由于2 < 4, 把2放入集合,,指针p1和p各右移一位;

比特截图2022-06-02-22-15-54.png

  • 由于3 < 4, 把3放入集合,,指针p1和p各右移一位;

比特截图2022-06-02-22-17-33.png

  • 由于 5 > 4, 把4放入集合,,指针p2和p各右移一位;

比特截图2022-06-02-22-19-20.png

  • 由于5 < 7, 把5放入集合,,指针p1和p各右移一位;

比特截图2022-06-02-22-21-35.png

  • 由于6 < 7, 把6放入集合,,指针p1和p各右移一位;

比特截图2022-06-02-22-22-57.png

到这个时候大家已经发现了,此时左侧的小集合已经没有元素可用

第三轮 :将另外一个还有剩余元素的集合中, 把剩余元素按顺序复制到大集合尾部去

比特截图2022-06-02-22-26-49.png

这样一来,就实现了两个有序的小集合就归并成了一个有序的大集合。

归并排序的代码实现

public static void mergeSort(int[] q, int l, int r) {
    int[] temp = new int[r - l + 1]; //创建大集合存放数组
    if (l >= r) return;
    int mid = l + r >> 1;
    mergeSort( q, l, mid);
    mergeSort( q, mid + 1, r);
    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r) {
        if (q[i] <= q[j]) temp[k++] = q[i++];
        else temp[k++] = q[j++];
    }
    while (i <= mid) temp[k ++ ] = q[i ++ ];
    while (j <= r) temp[k ++ ] = q[j ++ ]; //将剩余的数放进大集合

    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = temp[j]; //将大集合中的元素放回之前的数组

}


public static void main(String[] args) {
    int [] array = {3, 5, 2, 6, 4, 8, 7, 9};
    mergeSort(array, 0, array.length - 1);
    System.out.println(Arrays.toString(array));
}

下篇预告: 图解十大排序篇五 快速排序