图文并茂!一文教你掌握十大排序算法之归并排序

1. 归并排序原理介绍

归并排序是建立在归并操作上的一种排序算法,它是一种稳定排序算法,它的时间复杂度是O(nlogn)。

归并排序算法的核心在于分治(divide-and-conquer),分治法的思想:“分”是将一个问题分解成很多不同的小问题进行递归求解,“治”是将各个小问题的解重新凑合在一起组成最终的答案。

对序列[3, 5, 2, 1, 4, 6, 8, 7]进行归并排序,首先是“分”,分的过程可以看作是递归的过程,将一个序列不停地拆分成越来越小的子序列,每次分割子序列的位置都是数组长度的1/2,递归的深度为log_2n,针对下图序列的递归深度为3。

再来看“治”的部分,每一次“治”都是将两个有序的子序列合并成一个新的有序子序列。

以下图为例,子序列[3, 5]和子序列[1, 2]合并成一个新的子序列[1, 2, 3, 5];子序列[4, 6]和[7, 8]合并成为一个新的子序列[4, 6, 7, 8];子序列[1, 2, 3, 5]和子序列[4, 6, 7, 8]最终合并为一个新的子序列[1, 2, 3, 4, 5, 6, 7, 8],此时排序结束。

2. 代码实现

利用一个长度和原数组相同的temp数组,每次对两个子序列进行合并后的结果都存放到temp数组中,然后将temp数组中的有效元素拷贝到原数组中,这样可以保证在排序过程中只操作2个数组,不会产生额外的空间开销。如果不太明白可以参考下图:

/**
 * @author Zeng
 * @date 2020/3/1 10:35
 */
public class 归并排序 {

    public static void merge(int[] arr, int begin, int mid, int end, int[] temp) {
        System.out.print("begin:"+begin+";mid:"+mid+";end:"+end+";");
        int leftPtr = begin;
        int rightPtr = mid + 1;
        int tempPtr = 0;
        //左右两个子序列的元素由小到大放入temp数组中
        while (leftPtr <= mid && rightPtr <= end){
            if(arr[leftPtr] < arr[rightPtr]){
                temp[tempPtr++] = arr[leftPtr++];
            }else{
                temp[tempPtr++] = arr[rightPtr++];
            }
        }
        //将左边剩余的元素放入到temp数组中
        while (leftPtr <= mid){
            temp[tempPtr++] = arr[leftPtr++];
        }
        //将右边剩余的元素放入到temp数组中
        while (rightPtr <= end){
            temp[tempPtr++] = arr[rightPtr++];
        }
        //将temp数组中已经排好序的元素拷贝到arr数组中
        tempPtr = 0;
        while (begin <= end){
            arr[begin++] = temp[tempPtr++];
        }
        System.out.println("排序结果:"+Arrays.toString(arr));
    }

    public static void sort(int[] arr, int begin, int end, int[] temp){
        //分隔子数组
        if(begin < end){
            //获取分隔的下标
            int mid = (begin + end) >> 1;
            //对左边进行归并排序
            sort(arr, begin, mid, temp);
            //对右边进行归并排序
            sort(arr, mid + 1, end, temp);
            //左右两边进行合并
            merge(arr, begin, mid, end, temp);
        }
    }

    public static void mergeSort(int[] arr){
        //创建一个长度相同的暂存数组,避免频繁地创建子数组
        int[] temp = new int[arr.length];
        sort(arr, 0, arr.length - 1, temp);
        System.out.println(Arrays.toString(temp));
    }

    public static void main(String[] args) {
        int[] arr = new int[]{3, 5, 2, 1, 4, 6, 8, 7};
        mergeSort(arr);
    }

}
//begin:0;mid:0;end:1;排序结果:[3, 5, 2, 1, 4, 6, 8, 7]
//begin:2;mid:2;end:3;排序结果:[3, 5, 1, 2, 4, 6, 8, 7]
//begin:0;mid:1;end:3;排序结果:[1, 2, 3, 5, 4, 6, 8, 7]
//begin:4;mid:4;end:5;排序结果:[1, 2, 3, 5, 4, 6, 8, 7]
//begin:6;mid:6;end:7;排序结果:[1, 2, 3, 5, 4, 6, 7, 8]
//begin:4;mid:5;end:7;排序结果:[1, 2, 3, 5, 4, 6, 7, 8]
//begin:0;mid:3;end:7;排序结果:[1, 2, 3, 4, 5, 6, 7, 8]
//[1, 2, 3, 4, 5, 6, 7, 8]
发布了50 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_41949328/article/details/104601931