1. 引言

数组排序是Java中的常见操作,但有时我们还需要获取排序后元素的原始索引位置。这类信息在某些算法和应用场景中至关重要。本文将探讨在Java中实现这一需求的几种方法。

2. 问题描述

排序数组是基础操作,但某些场景下我们不仅需要按值排序,还需要保留元素的原始位置信息。当需要追踪元素在排序后的位置变化时,这种需求尤为关键。考虑以下数组:

int[] array = {40, 10, 20, 30};

排序前,元素的索引位置为:

  • 索引 0: 40
  • 索引 1: 10
  • 索引 2: 20
  • 索引 3: 30

排序后,元素的新索引位置为:

  • 索引 0: 10(原索引 1)
  • 索引 1: 20(原索引 2)
  • 索引 2: 30(原索引 3)
  • 索引 3: 40(原索引 0)

我们的目标是在对数组升序排序的同时,追踪元素基于排序值的索引变化情况。

3. 使用自定义比较器与索引

获取排序后索引的一种方法是使用自定义比较器,在排序过程中维护索引信息。这种方法允许我们基于元素值排序,同时保留原始位置信息。代码实现如下:

int[] array = {40, 10, 20, 30};

@Test
void givenArray_whenUsingCustomComparator_thenSortedIndicesMatchExpected() {
    Integer[] indices = new Integer[array.length];
    for (int i = 0; i < array.length; i++) {
        indices[i] = i;
    }

    Arrays.sort(indices, Comparator.comparingInt(i -> array[i]));

    assertArrayEquals(new Integer[]{1, 2, 3, 0}, indices);
}

关键点解析:

  1. 初始化indices数组存储原始索引
  2. 使用Arrays.sort()对索引数组排序
  3. 通过Comparator.comparingInt(i -> array[i])指定排序规则: ✅ 比较器实际比较的是array中对应索引位置的值 ✅ 排序过程中索引数组被重新排列
  4. 最终indices数组按array的值升序排列

⚠️ 注意:此方法会修改原始索引数组,确保使用副本操作。

4. 使用Java 8 Stream API

Java 8引入的Stream API提供了更简洁的处理方式。我们可以利用流操作获取并排序索引:

@Test
void givenArray_whenUsingStreamAPI_thenSortedIndicesMatchExpected() {
    List<Integer> indices = IntStream.range(0, array.length)
      .boxed().sorted(Comparator.comparingInt(i -> array[i])).collect(Collectors.toList());

    assertIterableEquals(Arrays.asList(1, 2, 3, 0), indices);
}

操作流程分解:

  1. IntStream.range(0, array.length) ✅ 生成0到length-1的整数流(原始索引)
  2. .boxed() ✅ 将基本类型流转换为包装类型流
  3. .sorted(Comparator.comparingInt(i -> array[i])) ✅ 核心排序逻辑:按array中对应索引位置的值排序
  4. .collect(Collectors.toList()) ✅ 将排序后的索引收集到List

这种方法更符合函数式编程风格,代码更简洁直观。

5. 结论

我们探讨了在Java中排序数组时保留元素原始索引的两种有效方法:

  1. 自定义比较器方案:适合需要直接操作数组的场景
  2. Stream API方案:代码更简洁,适合函数式编程风格

这些方法在需要维护元素位置关系的算法和应用中非常有价值。完整示例代码可在GitHub仓库获取。


原始标题:Get the Indices of an Array After Sorting in Java | Baeldung