java实现归并排序

401 阅读2分钟

归并排序

前言

第一篇文章,只是想随便写点啥。聊一下排序算法吧,时时勤拂拭。我们并不需要关注所有排序算法的实现,多数的作为了解即可。只有其中少数优秀且经典的排序算法我们才需要掌握。例如归并排序、快速排序、堆排序。本篇就来讲下归并排序。归并排序不仅是优秀的排序算法,所用到的分治法更是经典思路。

算法思路

整体思路

image.png

当你已经熟悉这个算法,仅仅看上面的图示已经可以把整个的排序过程了然于胸。首先将待排序的元素分成大小大致相等的两个子序列,然后再把子序列分成大小大致相等的两个子序列,如此下去,直到分解成一个元素为止。这时含有一个元素的子序列都是有序的。然后执行合并操作,将两个有序的子序列合并为一个有序序列,如此下去,直到所有的元素都合并为一个有序序列。

核心问题

整体的算法中涉及到两个问题,一是拆分数组成两个大小大致相等的数组,二是合并两个有序数组,问题一是容易解决的。问题在于问题二如何解决。我们首先申请一个大小足够的新数组,然后对两个有序数组本着谁当前元素小谁往新的数组插入。最后再处理下有剩余元素的数组即可。核心算法如下:

/**
 * 首先,实现下合并两个有序数组的方法,合并两个有序数组使得原来数组依旧有序,
 * 方法return时将合并的两个有序数组返回
 */
private static int[] mergeTwoSortedArray(int[] array1, int[] array2) {
    // 申请新数组
    int[] array = new int[array1.length + array2.length];
    // 定义各个数组标兵
    int i = 0, j = 0, k = 0;
    while (i < array1.length && j < array2.length) {
        if (array1[i] <= array2[j]) {
            array[k++] = array1[i++];
        } else {
            array[k++] = array2[j++];
        }
    }
    // 当上面的循环进行完毕之后,依旧可能存在未完成的数字归纳,那么我们归纳完成
    while (i < array1.length) {
        array[k++] = array1[i++];
    }

    while (j < array2.length) {
        array[k++] = array2[j++];
    }
    return array;
}

至此,我们的整个算法都可以完成了,如下:

import java.util.Arrays;

/**
 * 二路归并排序
 *
 * @author : wuwensheng
 * @date : 17:17 2021/11/9
 */
public class MergeSort {


    /**
     * 首先,实现下合并两个有序数组的方法,合并两个有序数组使得原来数组依旧有序,
     * 方法return时将合并的两个有序数组返回
     */
    private static int[] mergeTwoSortedArray(int[] array1, int[] array2) {
        System.out.println("prepare to merge array1:" + Arrays.toString(array1));
        System.out.println("prepare to merge array2:" + Arrays.toString(array2));
        // 申请新数组
        int[] array = new int[array1.length + array2.length];
        // 定义各个数组标兵
        int i = 0, j = 0, k = 0;
        while (i < array1.length && j < array2.length) {
            if (array1[i] <= array2[j]) {
                array[k++] = array1[i++];
            } else {
                array[k++] = array2[j++];
            }
        }
        // 当上面的循环进行完毕之后,依旧可能存在未完成的数字归纳,那么我们归纳完成
        while (i < array1.length) {
            array[k++] = array1[i++];
        }

        while (j < array2.length) {
            array[k++] = array2[j++];
        }
        System.out.println("merge two array result:" + Arrays.toString(array));
        return array;
    }

    private static int[] mergeSortMethod(int[] array) {
        // 当数组长度来到1的时候,可以执行归并了
        if (array.length <= 1) {
            return array;
        }
        // 首先,将数组拆为两个
        int number = array.length >> 1;
        int[] array1 = Arrays.copyOf(array, number);
        int[] array2 = Arrays.copyOfRange(array, number, array.length);
        System.out.println("original array:" + Arrays.toString(array));
        System.out.println("left array:" + Arrays.toString(array1));
        System.out.println("right array:" + Arrays.toString(array2));
        System.out.println("--------------------------------------");
        return mergeTwoSortedArray(mergeSortMethod(array1), mergeSortMethod(array2));
    }

    public static void main(String[] args) {
        int[] array2 = {35, 101, -88, 21, 1, -6, 9, -1, 44, 33};
        int[] ints = mergeSortMethod(array2);
        for (int anInt : ints) {
            System.out.println(anInt);
        }
    }
}

我们加入一些输出语句,来观察下整个运行过程:

image.png

非常清晰,先拆分再合并,本篇到此。