归并排序(排序系列)

125 阅读2分钟

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

继续更新我的排序系列吧,上期简单介绍了快速排序,这期就来说一下归并排序吧。

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。归并排序的时间复杂度为O(nlogn),当排序的量级越大时归并排序的时间复杂度的优势就越能体现出来。

算法步骤

  1. 找到中间节点,将左右两边进行递归归并排序
  2. 将排序好的左右两边进行合并

算法的步骤很简单,当我们要排序这样一个数组的时候,首先将这个数组分成一半。然后把左边的数组给排序,右边的数组给排序,之后呢再将它们归并起来。当递归到只有一个元素的时候那就是有序的数列了,之后再进行合并,而合并之后的数列也是有序的,于是就一步步合并完成整个数列

而难点就是怎么将两个有序的数列合并完成一个有序的数列,这个的算法思想就是另外开辟一个数组的空间,选择两个数列中最小的元素存入这个新开辟的空间里,直到两个序列的元素完全存入新开辟的数组里,再把数组里的元素有序的赋值到两个数列里,这样就完成了整个算法。

mergeSort.gif

上代码:

public static void mergeSort(int[] arr , int begin, int end) {
    //如果左边位置和右边相逢说明已经有序了,比如说一个元素的情况
     if (begin >= end) {
         return;
     }
     //找到中间节点
     int mid = (begin + end) / 2;
     //归并左边
     mergeSort(arr,begin,mid);
     //归并右边
     mergeSort(arr,mid+1,end);
     //合并数列
     merge(arr,begin,mid,end);
}
public static void merge(int[] arr, int begin, int mid, int end) {
    //开辟新的空间存储有序数列
    List<Integer> a = new ArrayList<>();
     int i = begin, j = mid + 1;
    //寻找最小的元素插入新的空间 这里是两边数列都没比较完的情况
    while (i <= mid && j <= end) {
        if (arr[i] < arr[j]) {
            a.add(arr[i]);
            i++;
        }else {
            a.add(arr[j]);
            j++;
        }
    }
    //当左边没比较完直接插入左边元素
    while ( i<= mid) {
        a.add(arr[i]);
        i++;
    }
     //当右边没比较完直接插入右边元素
    while (j <= end) {
        a.add(arr[j]);
        j++;
    }
    //把有序的数列重新赋值到合并的数组
    for (Integer temp : a) {
        arr[begin++] = temp;
    }
}