【算法】——归并排序,图解高效的归并排序算法

归并排序是一种稳定高效的排序,采用分治策略,将问题分解为一个个小的问题,然后解决

主要思想

  • 先分解,再归并
  1. 一次归并只能处理两个有序序列,所以需要将序列不断划分为更小的序列
  2. 当递归到最小的时候,每个小序列里只有一个元素,一定是有序的,所以可以进行归并
  3. 然后,因为这个归并之后的序列也是有序的了,所以可以和其它有序序列再进行归并,直到结束所有递归。

 其中每次如何将两个有序序列进行归并:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  4. 重复步骤3直到某一指针到达序列尾
  5. 将另一序列剩下的所有元素直接复制到合并序列尾

即可完成一次二路归并

(两个有序序列的归并和合并两个有序链表的思想很像)

动画演示

Java代码

package algorithm;

import java.util.Arrays;

public class Sort {

    // 归并排序
    private static void mergeSort(int[] array, int low, int high) {
        int mid = (high + low) / 2;
        if (low >= high) {
            return;
        }
        mergeSort(array, low, mid); // 递归前面的
        mergeSort(array, mid +1, high); // 递归后面的
        merge(array, low, mid, high); // 归并
    }
    // 归并
    private static void merge(int[] array, int low, int mid, int high) {
        // 创建一个临时数组,用于存放归并之后的结果
        int temp[] = new int[high - low + 1];
        int index = 0; // 临时数组的索引
        int i = low; // 前面数组的索引
        int j = mid + 1; // 后面数组的索引
        while (i <= mid && j <= high) {
            if (array[i] <= array[j]) {
                temp[index] = array[i];
                i++;
                index++;
            } else {
                temp[index] = array[j];
                j++;
                index++;
            }
        }
        // 将剩余的数组直接放入临时数组
        while (j <= high) {
            temp[index] = array[j];
            j++;
            index++;
        }
        while (i <= mid) {
            temp[index] = array[i];
            i++;
            index++;
        }
        // 把临时数组存入原数组
        System.arraycopy(temp, 0, array, low, temp.length);
    }

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

如上代码分析:

三个指针:

  • low:前面序列的指针
  • mid:两个序列的分界线
  • high:后面序列的指针

结束条件:

  • 因为不断递归划分,所以low、mid和hight指针在不断变化
  • 但low应该始终在high的左面
  • 所以,当low >= high的时候,就代表递归到最后一层,直接返回

递归:

  • 先递归划分前面序列(每次都递归前面的序列,直到递归到最底层,深度优先)
  • 然后当其中一个序列的前面序列递归返回后,我们就递归它后面的序列
  • 当前面和后面都递归到最底层返回的时候(一定是一个有序序列),我们就将它们进行归并

归并(二路归并):

  • 先创建一个临时数组temp,用于存放归并之后的序列
  • 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  • 比较两个指针所指向的元素,选择相对小的元素放入到 temp 中,并移动指针到下一位置
  • 重复执行步骤3,直到其中一个指针达到序列尾部
  • 最后将另一个序列剩余的元素,直接全部放入temp中
  • 再将temp同步到原数组中即可(注意放置的位置)

重复上述操作,直到所有递归结束

时间复杂度

最好情况:O(nlogn)

平均情况:O(nlogn)

最坏情况:O(nlogn)

发布了34 篇原创文章 · 获赞 20 · 访问量 6974

猜你喜欢

转载自blog.csdn.net/weixin_42193813/article/details/105192050