基于归并排序算法的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("]"); } }
关键改动说明
- 返回值调整:将
mergesort和merge方法改为返回long类型的逆序数(避免数组过大时int溢出)。 - 递归累加:
mergesort中递归计算左右子数组的逆序数,再加上合并阶段的逆序数,返回总和。 - 合并阶段计数:在
merge方法中,当右子数组元素小于左子数组元素时,累加leftSize - i到计数器,这就是当前右元素对应的逆序对数量。
运行代码后,输出的逆序数为18,和你手动统计的结果一致。
内容的提问来源于stack exchange,提问作者gmnpjpn
相关产品推荐
相关产品推荐

