You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于归并排序算法的Java数组逆序数统计实现问题

归并排序统计逆序数的实现方法

你手动统计的18个逆序是正确的,通过修改归并排序的合并(merge)阶段来统计逆序数是最高效的方式(时间复杂度O(nlogn)),核心逻辑和你绘制的思路图一致:

在合并有序的左右子数组时,若右子数组的当前元素小于左子数组的当前元素,那么左子数组中从当前位置到末尾的所有元素,都会和这个右元素构成逆序对,此时计数器需要累加左子数组剩余元素的数量(leftSize - i)。同时,递归统计左右子数组内部的逆序数,最终总和就是整个数组的逆序数。

修改后的完整代码

public class MergesortAlgorithm{

    public static void main(String[] args) {
        int[] array = {1, 5, 4, 8, 10, 2, 6, 9, 12, 11, 3, 7};

        System.out.println("Original array:");
        printArray(array);
        long inversionCount = mergesort(array);

        System.out.println("\nOrdered array:");
        printArray(array);

        System.out.println("\nNumber of inversions: " + inversionCount);
    }
    
    public static long mergesort (int[] array){
        int inputLength = array.length;
        if (inputLength < 2){
            return 0; // 单个元素无逆序
        }

        int midIndex = array.length / 2;
        int[] leftHalf = new int [midIndex];
        int[] rightHalf = new int [inputLength - midIndex];

        for (int i = 0; i < midIndex; i++) {
            leftHalf[i] = array[i];
        }

        for (int i = midIndex; i < array.length; i++) {
            rightHalf[i-midIndex] = array[i];
        }        
        
        // 累加左、右子数组内部逆序数 + 合并阶段跨子数组的逆序数
        long leftInversions = mergesort(leftHalf);
        long rightInversions = mergesort(rightHalf);
        long mergeInversions = merge(array, leftHalf, rightHalf);

        return leftInversions + rightInversions + mergeInversions;
    }

    public static long merge (int[] array, int[] leftHalf, int[] rightHalf){
        int leftSize = leftHalf.length;
        int rightSize = rightHalf.length;
        int i = 0, j = 0, k = 0;
        long inversions = 0;

        while (i < leftSize && j < rightSize) {
            if (leftHalf[i] <= rightHalf[j]) {
                array[k] = leftHalf[i];
                i++;
            }
            else {
                array[k] = rightHalf[j];
                j++;
                // 左子数组剩余的所有元素都和当前右元素构成逆序
                inversions += leftSize - i;
            }
            k++;
        }

        // 处理剩余元素,这部分不会产生新的逆序
        while (i < leftSize) {
            array[k] = leftHalf[i];
            i++;
            k++;
        }

        while (j < rightSize) {
            array[k] = rightHalf[j];
            j++;
            k++;
        }
        return inversions;
    }

    public static void printArray (int[] array) {
        System.out.printf("[ ");
        for (int num : array) {
            System.out.printf("%d ", num);
        }
        System.out.println("]");
    }
}

关键改动说明

  1. 返回值调整:将mergesort和merge方法改为返回long类型的逆序数(避免数组过大时int溢出)。
  2. 递归累加:mergesort中递归计算左右子数组的逆序数,再加上合并阶段的逆序数,返回总和。
  3. 合并阶段计数:在merge方法中,当右子数组元素小于左子数组元素时,累加leftSize - i到计数器,这就是当前右元素对应的逆序对数量。

运行代码后,输出的逆序数为18,和你手动统计的结果一致。

内容的提问来源于stack exchange,提问作者gmnpjpn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 20:42:26