排序算法之归并排序

排序算法之归并排序

经典排序算法有冒泡排序,插入排序,选择排序,归并排序,快速排序,计数排序,基数排序,桶排序。咱们最了解的应该就是冒泡排序,插入排序,选择排序,这里我们就一起学习一下归并排序。

核心思想

归并排序的核心思想其实非常简单,就是把数组两两分解,将分解好的两部分排序,最后再合并在一起,这样最后整个数组就是有序的了。归并排序采用的是分治思想,将一个大问题分解为若干个小问题解决,小的问题解决了,大问题自然迎刃而解。分治的思想和递归挺相似,递归是代码上的体现,而分治是解决问题的思路,这里我们就采用递归实现归并排序。
例如数组
{3,2,5,4,1,3,8,7}=>{3,2,5,4}+{1,3,8,7}=>{3,2}+{5,4}+{1,3}+{8,7}=>{3}+{2}+{5}+{4}+{1}+{3}+{8}+{7}=>{2,3}+{4,5}+{1,3}+{7,8}=>{2,3,4,5}+{1,3,7,8}=>{1,2,3,3,4,5,7,8}

代码实现

因为我们知道,归并排序就是将数组分解,排序,整合,如果分解后的数组还能再分解,那么就继续分解,直至无法分解为止。这里我们就可以写出递归公式,mergeSort(p...r)=merge(mergeSort(p...q),mergeSort(q+1...r)),这里q=(p+r)/2mergeSort(p...r)中p和r是指数组中下标为p到r的数据,merge方法是合并两个数组的同时去排序。
递归的终止条件也就是无法再分解,即p>=r
递推公式我们写出来了,代码写起来也就比较容易了。

package com.test;

import java.util.Arrays;

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

    /**
     * @param arr, n
     * @return: void
     * @Title:
     * @Description: 递归调用
     * @date: 23:56 2021/3/21 0021
     * Modification History:
     * Date                Author        Description
     *-------------------------------------------*
     *  23:56 2021/3/21 0021      xx.huang       修改原因
     */
    static void mergeSort(int[] arr, int n) {
        mergeSortA(arr, 0, n - 1);
    }

    /**
     * @param arr, p, r
     * @return: void
     * @Title:
     * @Description: 往下分解数组
     * @date: 23:56 2021/3/21 0021
     * Modification History:
     * Date                Author        Description
     *-------------------------------------------*
     *  23:56 2021/3/21 0021      xx.huang       修改原因
     */
    static void mergeSortA(int[] arr, int p, int r) {
        if (p >= r) {
            return;
        }
        int q = (p + r) / 2;
        mergeSortA(arr, p, q);
        mergeSortA(arr, q + 1, r);
        merge(arr, p, q, r);
    }

    /**
     * @param arr, p, q, r
     * @return: void
     * @Title:
     * @Description: 排序合并数组
     * @date: 23:56 2021/3/21 0021
     * Modification History:
     * Date                Author        Description
     *-------------------------------------------*
     *  23:56 2021/3/21 0021      xx.huang       修改原因
     */
    static void merge(int[] arr, int p, int q, int r) {
        int[] temp = new int[r - p + 1];
        int i = p;
        int j = q + 1;
        int k = 0;
        while (i <= q && j <= r) {
            if (arr[i] <= arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];
            }
        }
        if (i <= q) {
            while (i <= q) {
                temp[k++] = arr[i++];
            }
        } else if (j <= r) {
            while (j <= r) {
                temp[k++] = arr[j++];
            }
        }
        for (int s = 0; s <= r - p; s++) {
            arr[p + s] = temp[s];
        }
    }
}

通过我的注释就可以知道每个方法的作用,我们着重来解释merge方法。因为我们知道归并排序是拆分数组再排序,但是实际上我们并没有真正的拆分数组,还是在原数组也就是arr上面操作的,我们每次操作的数据数量是r-p+1,所以我们需要创建一个临时数组temp存放这些数据。虽然我们在代码中没有真正的把数组拆开,但是思路上确实是当作被分割了的数组,我们知道根据分治的思想,最后是被拆成若干个无法被继续分割的数组,然后往回排序合并,我们每次是要操作两个数组(思想上当作两个数组,实际还是在一个数组中),p即需要往回合并排序数组1的起始下标,q+1是往回合并排序数组2的起始下标,当数组无法被继续分割的时候,实际上每个数组就只有一个元素(再强调一下,实际代码中并没有拆分数组,只是思路上确实是这么想的),然后根据后面的排序代码进行两个数组的排序,最后把排序好的数组temp放回arr数组中,如此递归,最后的数组就是有序的了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值