归并排序算法

123 阅读3分钟

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

本文系作者 不太自律的程序猿原创,转载请私信并在文章开头附带作者和原文地址链接。

归并排序算法

归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

算法思路

归并排序是用分治思想,分治模式在每一层递归上有三个步骤:

  • 分解(Divide) :将n个元素分成个含n/2个元素的子序列。
  • 解决(Conquer) :用合并排序法对两个子序列递归的排序。
  • 合并(Combine) :合并两个已排序的子序列已得到排序结果。

2. 实现逻辑

2.1 迭代法

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

2.2 递归法

① 将序列每相邻两个数字进行归并操作,形成floor(n/2)个序列,排序后每个序列包含两个元素
② 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素
③ 重复步骤②,直到所有元素排序完毕

1654574163267.png

image.png

代码实现

/**
 * 归并排序
 * @Author distance
 */
public class MergeSort {

    public static void merge(int[] num, int left, int mid, int right, int[] temp) {
        //一个新的数组,将原数组映射进去
        for (int i = left; i <= right; i++) {
            temp[i] = num[i];
        }

        // 序列1 left ~ mid	  序列2 mid+1 ~ right
        // 有序合并
        int headL = left, headR = mid + 1; // headL 和 headR 分别指向两个序列开头部分
        int head = left; // 原序列起点

        while (headL <= mid && headR <= right) {
            if (temp[headL] < temp[headR]) {
                num[head ++] = temp[headL];
                headL ++;
            } else {
                num[head ++] = temp[headR];
                headR ++;
            }
        }

        while (headL <= mid) {
            num[head ++] = temp[headL];
            headL ++;
        }

        while (headR <= right) {
            num[head ++] = temp[headR];
            headR ++;
        }
    }

    public static void mergeSort(int[] num, int left, int right, int[] temp) {
        if (left >= right) {
            return;
        }

        int mid = (left + right) / 2;
        mergeSort(num, left, mid, temp);
        mergeSort(num, mid + 1, right, temp);

        merge(num, left, mid, right, temp);
    }

    public static void sort(int[] num) {
        int[] temp = new int[num.length];
        mergeSort(num, 0, num.length - 1, temp);
    }

    public static void main(String[] args) {
        int[] arr = {8,1,2,7,6,5,4,3}; 
        System.out.println("排序前:"+Arrays.toString(arr)); 
        MergeSort.sort(arr);
        System.out.println("排序后:"+Arrays.toString(arr));       
    }
}

1654574163267.png

算法性能分析

不管元素在什么情况下都要做这些步骤,所以花销的时间是不变的,所以该算法的最优时间复杂度和最差时间复杂度及平均时间复杂度都是一样的为:O( nlogn )

归并的空间复杂度就是那个临时的数组和递归时压入栈的数据占用的空间:n + logn;所以空间复杂度为: O(n)。

归并排序算法中,归并最后到底都是相邻元素之间的比较交换,并不会发生相同元素的相对位置发生变化,故是稳定性算法。

感谢诸君的观看,文中如有纰漏,欢迎在评论区来交流。如果这篇文章帮助到了你,欢迎点赞👍关注。