排序算法 归并排序(普通归并排序、自然归并排序)

一、归并排序

1、介绍。

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

        归并排序是稳定排序,需要额外内存,空间复杂度O(n)。时间复杂度,最佳情况:O(nlogn)  最差情况:O(nlogn)  平均情况:O(nlogn)。

2、步骤。

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

3、代码。

public static void main(String[] args) {
        System.out.println("------开始------");
        //生成生成两份一模一样的随机数组,其中一组用系统自带的方法进行排序,到时候进行验证。
        final int number = 100000;
        int[] sortArray = new int[number];
        int[] sortArrayCopy = new int[number];
        for (int i = 0; i < sortArray.length; i++) {
            sortArray[i] = (int) (Math.random() * number);
        }
        System.arraycopy(sortArray, 0, sortArrayCopy, 0, number);//数组复制
        Arrays.sort(sortArrayCopy);

        //开始排序
        long startTime = System.currentTimeMillis();
        mergeSort(sortArray);//归并(合并)排序
        System.out.println("花费时间:" + (System.currentTimeMillis() - startTime));

        //跟系统排序之后数组进行比较,查看是否排序成功。
        if (Arrays.equals(sortArray, sortArrayCopy)) {
            System.out.println("排序成功");
        } else {
            System.out.println("排序失败");
        }
        System.out.println("------结束------");
    }
//归并(合并)排序 最佳情况:T(n) = O(n)  最差情况:T(n) = O(nlogn)  平均情况:T(n) = O(nlogn)
private static void mergeSort(int[] array) {
    //只剩一个数了
    if (array.length < 2) {
        return;
    }
    //将array数组,切成left和right两个数组
    int middle = array.length / 2;
    int[] left = new int[middle];
    int[] right = new int[array.length - middle];
    for (int i = 0; i < array.length; i++) {
        if (i < middle) {
            left[i] = array[i];
        } else {
            right[i - middle] = array[i];
        }
    }
    //递归
    mergeSort(left);
    mergeSort(right);
    merge(array, left, right);
}
private static void merge(int[] array, int[] left, int[] right) {
    int leftIndex = 0, rightIndex = 0;
    for (int i = 0; i < array.length; i++) {
        if (leftIndex >= left.length) {//left数组已经排完了
            array[i] = right[rightIndex++];
        } else if (rightIndex >= right.length) {//right数组已经排完了
            array[i] = left[leftIndex++];
        } else if (left[leftIndex] < right[rightIndex]) {//left数组的值小于right数组的值
            array[i] = left[leftIndex++];
        } else {//left数组的值大于等于right数组的值
            array[i] = right[rightIndex++];
        }
    }
}

4、结果。

排序算法 归并排序(普通归并排序、自然归并排序)_第1张图片

二、自然归并排序

1、介绍。

        自然归并排序:对于初始给定的数组,通常存在多个长度大于1的已自然排好序的子数组段.例如,若数组a中元素为{4,8,3,7,1,5,6,2},则自然排好序的子数组段有{4,8},{3,7},{1,5,6},{2}.用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段.然后将相邻的排好序的子数组段两两合并,构成更大的排好序的子数组段({3,4,7,8},{1,2,5,6}).继续合并相邻排好序的子数组段,直至整个数组已排好序。

        自然归并排序是稳定排序,需要额外内存,空间复杂度O(n)。时间复杂度,最佳情况:O(nlogn)  最差情况:O(nlogn)  平均情况:O(nlogn)。

2、步骤。

        跟归并排序的步骤一样,只不过在选择middle的时候,将前面已经排序好的作为一个数组。

3、代码。

public static void main(String[] args) {
        System.out.println("------开始------");
        //生成生成两份一模一样的随机数组,其中一组用系统自带的方法进行排序,到时候进行验证。
        final int number = 100000;
        int[] sortArray = new int[number];
        int[] sortArrayCopy = new int[number];
        for (int i = 0; i < sortArray.length; i++) {
            sortArray[i] = (int) (Math.random() * number);
        }
        System.arraycopy(sortArray, 0, sortArrayCopy, 0, number);//数组复制
        Arrays.sort(sortArrayCopy);

        //开始排序
        long startTime = System.currentTimeMillis();
        natureMergeSort(sortArray);//自然归并(合并)排序
        System.out.println("花费时间:" + (System.currentTimeMillis() - startTime));

        //跟系统排序之后数组进行比较,查看是否排序成功。
        if (Arrays.equals(sortArray, sortArrayCopy)) {
            System.out.println("排序成功");
        } else {
            System.out.println("排序失败");
        }
        System.out.println("------结束------");
    }
//自然归并(合并)排序 最佳情况:T(n) = O(n)  最差情况:T(n) = O(nlogn)  平均情况:T(n) = O(nlogn)
private static void natureMergeSort(int[] array) {
    //只剩一个数了
    if (array.length < 2) {
        return;
    }
    //将array数组,切成left和right两个数组
    int middle = array.length / 2;
    for (int i = 0; i < array.length - 1; i++) {
        if (array[i] > array[i + 1]) {
            middle = i;
            break;
        }
    }
    int[] left = new int[middle];
    int[] right = new int[array.length - middle];
    for (int i = 0; i < array.length; i++) {
        if (i < middle) {
            left[i] = array[i];
        } else {
            right[i - middle] = array[i];
        }
    }
    //递归
    mergeSort(left);
    mergeSort(right);
    merge(array, left, right);
}
private static void merge(int[] array, int[] left, int[] right) {
    int leftIndex = 0, rightIndex = 0;
    for (int i = 0; i < array.length; i++) {
        if (leftIndex >= left.length) {//left数组已经排完了
            array[i] = right[rightIndex++];
        } else if (rightIndex >= right.length) {//right数组已经排完了
            array[i] = left[leftIndex++];
        } else if (left[leftIndex] < right[rightIndex]) {//left数组的值小于right数组的值
            array[i] = left[leftIndex++];
        } else {//left数组的值大于等于right数组的值
            array[i] = right[rightIndex++];
        }
    }
}

4、结果。

排序算法 归并排序(普通归并排序、自然归并排序)_第2张图片

你可能感兴趣的:(算法)