Algorithm basis - merge sort and its application

Keywords: Java Algorithm data structure

I wrote a related article two years ago: Sorting algorithm - merge sorting The reason why we have another article today is that we have a deeper understanding of this algorithm.

Algorithm analysis

Here, we will paste the dynamic diagram of merge sorting algorithm again:
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-7hhlsvjq-1630854524138)( http://coolwrite.cn/wp-content/uploads/2021/08/mergesort.gif )]

differ Bubbling,choice,insert The implementation idea of sorting algorithm and merging sorting avoids the waste of a large number of comparison behaviors: first, fine-grained grouping sorting of elements is carried out. Although only local order is achieved, the efficiency is improved from O(n^2) to O(n * log n) by gradually expanding the grouping size and making full use of the comparison results retained in the intermediate process

code implementation

Recursive implementation

/**
 * @description: Merge sort
 * @author: Flash
 * @create: 2021-08-20
 **/
public class Code04_MergeSort {

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

    private static void process(int[] arr, int L, int R) {
        if (L == R) {
            return;
        }
        int mid = L + ((R - L) >> 2);
        process(arr, L, mid);
        process(arr, mid + 1, R);

        merge(arr, L, mid, R);
    }

    private static void merge(int[] arr, int left, int mid, int right) {
        int point1 = left;
        int point2 = mid + 1;

        int[] help = new int[right - left + 1];
        int i = 0;

        while (point1 <= mid && point2 <= right) {
            help[i++] = arr[point1] <= arr[point2] ? arr[point1++] : arr[point2++];
        }

        while (point1 <= mid) {
            help[i++] = arr[point1++];
        }

        while (point2 <= right) {
            help[i++] = arr[point2++];
        }

        i = 0;
        for (int j = left; j <= right; j++) {
            arr[j] = help[i++];
        }
    }
}

Iterative implementation

The merge method is implemented in the same way as recursion and is omitted here.

// Merge and sort by iteration
private static void mergeSort2(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }
    int n = arr.length;

    // Each merge procedure is mergeSize * 2
    int mergeSize = 1;
    while (mergeSize < n) {

        int left = 0;
        while (left < n) {
            if (n - left <= mergeSize) {
                break;
            }

            // Notice that this is a subscript, so subtract one
            int mid = left + mergeSize - 1;
            // Note that this may be out of bounds, so a smaller value is taken
            int right = Math.min(mid + mergeSize, n - 1);
            merge(arr, left, mid, right);

            left = right + 1;
        }

        // Note that this is only to ensure that the mergeSize does not cross the boundary when moving left and does not affect the overall logic
        if (mergeSize > n / 2) {
            break;
        }
        mergeSize <<= 1;
    }
}

Application of merge sort

The merging process has some other uses because it can compare the size of the left and right array elements and its local order.

Reverse order pairs in an array

Please refer to: https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/

In the process of merge, by comparing the left and right elements, we can accumulate the process of reverse order pairs, and merge sorting is used as a package of this solution. Otherwise, the complexity of double traversal algorithm is O(n^2):

/**
 * @description: Reverse pair in array - < URL > https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/  </url>
 * @author: Flash
 * @create: 2021-08-20
 **/
public class Code05_MergeSortForReversePairs {

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

    private static int process(int[] arr, int L, int R) {
        if (L == R) {
            return 0;
        }
        int mid = L + ((R - L) >> 1);
        return process(arr, L, mid)
                + process(arr, mid + 1, R)
                + merge(arr, L, mid, R);
    }

    private static int merge(int[] arr, int left, int mid, int right) {
        int point1 = left;
        int point2 = mid + 1;

        int[] help = new int[right - left + 1];
        int i = 0;

        int res = 0;

        while (point1 <= mid && point2 <= right) {
			// Only here is modified: the number of cumulative reverse order pairs
            if (arr[point2] < arr[point1]) {
                res += mid - point1 + 1;
            }
            help[i++] = arr[point1] <= arr[point2] ? arr[point1++] : arr[point2++];
        }

        while (point1 <= mid) {
            help[i++] = arr[point1++];
        }

        while (point2 <= right) {
            help[i++] = arr[point2++];
        }

        i = 0;
        for (int j = left; j <= right; j++) {
            arr[j] = help[i++];
        }
        return res;
    }
}

Minimum sum

In an array, the sum of numbers smaller than it on the left of a number is called the small sum of numbers, and the small sum of all numbers is added up, called the small sum of array. Find the small sum of arrays.
Example: [1,3,4,2,5]
1 the number smaller than 1 on the left: No
3 the number smaller than 3 on the left: 1
4 the number smaller than 4 on the left: 1, 3
2 the number smaller than 2 on the left: 1
5 numbers smaller than 5 on the left: 1, 3, 4, 2
Therefore, the small sum of the array is: 1 + 1 + 3 + 1 + 1 + 3 + 4 + 2 = 16

The implementation process is similar to that of the reverse order pair above. Only the merge method code is given here:

private static int merge(int[] arr, int l, int mid, int r) {
    int pl = l;
    int pr = mid + 1;

    int[] help = new int[r - l + 1];
    int i = 0;

    int res = 0;
    while (pl <= mid && pr <= r) {
        res += arr[pl] < arr[pr] ? (r - pr + 1) * arr[pl] : 0;
        // Note: when the elements on both sides are equal, move the right pointer to avoid less calculation than the elements on the left
        help[i++] = arr[pl] < arr[pr] ? arr[pl++] : arr[pr++];
    }

    while (pl <= mid) {
        help[i++] = arr[pl++];
    }

    while (pr <= r) {
        help[i++] = arr[pr++];
    }

    i = 0;
    for (int j = l; j <= r; j++) {
        arr[j] = help[i++];
    }
    return res;
}

Posted by jrschwartz on Sun, 05 Sep 2021 20:58:10 -0700