1, the introduction

Merge sort is an efficient sorting algorithm based on merge operation. This algorithm is a very typical application of Divide and Conquer. Merge the ordered subsets to get a completely ordered set. That is, first order each subset, and then order between subsets. If two ordered sets are merged into one ordered set, it is called 2-way merging.

2, analysis,

  1. Divide the input set of length N into two subsets of length N /2;
  2. Merge sort is used for these two subsets respectively.
  3. Merge the two sorted subsets into a final sorted set.

Merge to order the whole thing

3, implementation,

3.1, the recursion


/ * * *@description: merge sort - recursive implementation *@author: erlang
 * @since: "* / 2020-09-28
public class MergeSort {

    /** * recursively sort **@paramArr Array to be sorted */
    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }

        process(arr, 0, arr.length - 1);
    }

    / * * *@paramArr Array to process *@paramLeft Left border *@paramRight has boundaries */
    private static void process(int[] arr, int left, int right) {
        if (left == right) {
            return;
        }
        int mid = left + ((right - left) >> 1);
        process(arr, left, mid);
        process(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }

    /** * merge **@paramArr handles arrays *@paramLeft Left border *@paramMid Indicates the middle boundary *@paramRight right border */
    public static void merge(int[] arr, int left, int mid, int right) {
        int[] help = new int[right - left + 1];
        int index = 0;
        int p1 = left;
        int p2 = mid + 1;
        while (p1 <= mid && p2 <= right) {
            help[index++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }

        // Store the rest of the elements in [left, mid] or [mid + 1, right] into the help array
        while (p1 <= mid) {
            help[index++] = arr[p1++];
        }

        while (p2 <= right) {
            help[index++] = arr[p2++];
        }

        // Put the elements in help back into the [left, right] range of arR
        for (int i = 0; i < help.length; i++) { arr[left + i] = help[i]; }}public static void main(String[] args) {
        ArraySortUtils.testSort(MergeSort::mergeSort, 100.100); }}Copy the code

3.2, iterations,


/ * * *@description: merge sort - iterative implementation *@author: erlang
 * @since: the 2020-09-28 22:55 * /
public class MergeSort {

    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int n = arr.length;

        // Currently ordered, left length
        int mergeSize = 1;

        while (mergeSize < n) {

            int left = 0;

            while (left < n) {
                int mid = left + mergeSize - 1;

                if (mid >= n) {
                    break;
                }

                int right = Math.min(mid + mergeSize, n - 1);

                merge(arr, left, mid, right);

                left = right + 1;
            }

            // If mergeSize is greater than half the array length, the array is completely sorted
            Prevent mergeSize << 1 from exceeding the length of int
            if (mergeSize > (n >> 1)) {
                break;
            }

            // Double each time
            mergeSize <<= 1; }}/** * merge **@paramArr handles arrays *@paramLeft Left border *@paramMid Indicates the middle boundary *@paramRight right border */
    public static void merge(int[] arr, int left, int mid, int right) {
        int[] help = new int[right - left + 1];
        int index = 0;
        int p1 = left;
        int p2 = mid + 1;
        while (p1 <= mid && p2 <= right) {
            help[index++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }

        while (p1 <= mid) {
            help[index++] = arr[p1++];
        }

        while (p2 <= right) {
            help[index++] = arr[p2++];
        }

        for (int i = 0; i < help.length; i++) { arr[left + i] = help[i]; }}public static void main(String[] args) {
        ArraySortUtils.testSort(MergeSort::mergeSort, 100.100); }}Copy the code

4, in actual combat

4.1 decimals and

4.4.1, description,

In an array, the sum of the smaller numbers to the left of a number is called the sum of the smallest numbers, and the sum of the smallest numbers is called the sum of the array. Find the small sum of arrays.

Example:,3,4,2,5 [1]

  1. The number to the left of 1 less than 1: none
  2. The number to the left of 3 less than 3:1
  3. Numbers to the left of 4 less than 4:1, 3
  4. The number to the left of 2 less than 2:1
  5. Numbers less than 5 to the left of 5:1, 3, 4, 2
  6. So the small sum of the array is 1+1+3+1+1+3+4+2=16
4.1.2, implementation,

/ * * *@description: small and *@author: erlang
 * @since: the 2020-10-13 21:49 * /
public class SmallSum {

    public static int smallSum(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        return process(arr, 0, arr.length - 1);
    }

    private static int process(int[] arr, int left, int right) {

        if (left == right) {
            return 0;
        }

        int mid = left + ((right - left) >> 1);

        return process(arr, left, mid)
                +
                process(arr, mid + 1, right)
                +
                merge(arr, left, mid, right);
    }

    private static int merge(int[] arr, int left, int mid, int right) {
        int[] help = new int[right - left + 1];
        int index = 0;
        int p1 = left;
        int p2 = mid + 1;
        int sum = 0;
        while (p1 <= mid && p2 <= right) {
            sum += arr[p1] < arr[p2] ? (right - p2 + 1) * arr[p1] : 0;
            help[index++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }

        while (p1 <= mid) {
            help[index++] = arr[p1++];
        }

        while (p2 <= right) {
            help[index++] = arr[p2++];
        }

        for (int i = 0; i < help.length; i++) {
            arr[left + i] = help[i];
        }
        return sum;
    }
    // for test
    public static int comparator(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        int res = 0;
        for (int i = 1; i < arr.length; i++) {
            for (int j = 0; j < i; j++) {
                res += arr[j] < arr[i] ? arr[j] : 0; }}return res;
    }

    // for test
    public static void main(String[] args) {
        int testTime = 500000;
        int maxSize = 10;
        int maxValue = 100;
        boolean succeed = true;
        for (int i = 0; i < testTime; i++) {
            int[] arr1 = ArraySortUtils.generateRandomArray(maxSize, maxValue);
            int[] arr2 = ArraySortUtils.copyArray(arr1);
            int smallSum = smallSum(arr1);
            int comparator = comparator(arr2);
            if(smallSum ! = comparator) { System.out.println("smallSum ==> " + smallSum);
                System.out.println("comparator ==> " + comparator);
                succeed = false;
                ArraySortUtils.printArray(arr1);
                ArraySortUtils.printArray(arr2);
                break;
            }
        }
        System.out.println(succeed ? "Nice!" : "Fail!"); }}Copy the code

4.2,Pairs of inversions in an array

2, description,

Two digits in an array form a reverse pair if the preceding digit is larger than the following digit. Enter an array and find the total number of inversions in the array.

Example 1:

Input:,5,6,4 [7]

Output: 5

4.2.2, implementation,
class Solution {
    public int reversePairs(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }

        return process(nums, 0, nums.length - 1);
    }

     private static int process(int[] arr, int left, int right) {

        if (left == right) {
            return 0;
        }

        int mid = left + ((right - left) >> 1);

        return process(arr, left, mid)
                +
                process(arr, mid + 1, right)
                +
                merge(arr, left, mid, right);
    }

    private static int merge(int[] arr, int left, int mid, int right) {
        int[] help = new int[right - left + 1];
        int index = 0;
        int p1 = left;
        int p2 = mid + 1;
        int sum = 0;
        while (p1 <= mid && p2 <= right) {
            sum += arr[p1] > arr[p2] ? (right - p2 + 1) : 0;
            help[index++] = arr[p1] > arr[p2] ? arr[p1++] : arr[p2++];
        }

        while (p1 <= mid) {
            help[index++] = arr[p1++];
        }

        while (p2 <= right) {
            help[index++] = arr[p2++];
        }

        for (int i = 0; i < help.length; i++) {
            arr[left + i] = help[i];
        }
        returnsum; }}Copy the code

5. Tool classes

5.1, MergeSortUtils


/ * * *@description: merge sort utility class *@author: erlang
 * @since: the 2020-10-12 22:32 * /
public class MergeSortUtils {

    /** * merge **@paramArr handles arrays *@paramLeft Left border *@paramMid Indicates the middle boundary *@paramRight right border */
    public static void merge(int[] arr, int left, int mid, int right) {
        int[] help = new int[right - left + 1];
        int index = 0;
        int p1 = left;
        int p2 = mid + 1;
        while (p1 <= mid && p2 <= right) {
            help[index++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }

        while (p1 <= mid) {
            help[index++] = arr[p1++];
        }

        while (p2 <= right) {
            help[index++] = arr[p2++];
        }

        for (int i = 0; i < help.length; i++) { arr[left + i] = help[i]; }}}Copy the code

5.2, ArraySortUtils


import java.util.Arrays;
import java.util.function.Consumer;

/ * * *@description: Array sort tool *@author: erlang
 * @since: the 2020-08-29 and * /
public class ArraySortUtils {

    /** * Randomly generates the array to be tested **@paramMaxSize Maximum array length *@paramMaxValue The largest value * in the array@returnReturns the generated array */
    public static int[] generateRandomArray(int maxSize, int maxValue) {
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
        }
        return arr;
    }

    /** * outputs the element ** of the array@paramArray arr * /
    public static void printArray(int[] arr) {
        System.out.println("");
        System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++START");
        for (int value : arr) {
            System.out.print(value + "");
        }
        System.out.println("");
        System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++END");
    }

    public static void comparator(int[] arr) {
        Arrays.sort(arr);
    }

    /** * re-copy a new array **@paramArr Array to copy *@returnReturns the copied new array */
    public static int[] copyArray(int[] arr) {
        if (arr == null) {
            return null;
        }
        int[] res = new int[arr.length];
        System.arraycopy(arr, 0, res, 0, arr.length);
        return res;
    }

    /** * compares whether the elements of two arrays are equal **@paramArr1 Array 1 * to be compared@paramArr2 The array to compare 2 star@returnReturns the verification result true/false */
    public static boolean isEqual(int[] arr1, int[] arr2) {
        if (arr1 == null && arr2 == null) {
            return true;
        }
        if (arr1 == null || arr2 == null) {
            return false;
        }
        if(arr1.length ! = arr2.length) {return false;
        }
        for (int i = 0; i < arr1.length; i++) {
            if(arr1[i] ! = arr2[i]) {return false; }}return true;
    }

    /** * Test whether the sorting result of the sorting method is correct **@paramThe consumer calls back the user - defined sorting method *@paramMaxSize Maximum array length *@paramMaxValue Specifies the largest number in the array, i.e. 0-maxValue */
    public static void testSort(Consumer<int[]> consumer, int maxSize, int maxValue) {
        int testTime = 5000;
        boolean succeed = true;
        for (int i = 0; i < testTime; i++) {
            // Generate a new array
            int[] arr1 = ArraySortUtils.generateRandomArray(maxSize, maxValue);
            // Copy the new array
            int[] arr2 = copyArray(arr1);
            // Call back the user-defined sort method to sort arri1
            consumer.accept(arr1);
            // Use the system's own sorting method to sort arr2
            comparator(arr2);
            // Compare the results of the two treatments
            if(! isEqual(arr1, arr2)) { succeed =false;
                printArray(arr1);
                printArray(arr2);
                break; }}// Outputs test results
        System.out.println(succeed ? "Nice!" : "Fail!"); }}Copy the code