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);
}
关键点解析:
- 初始化
indices
数组存储原始索引 - 使用
Arrays.sort()
对索引数组排序 - 通过
Comparator.comparingInt(i -> array[i])
指定排序规则: ✅ 比较器实际比较的是array
中对应索引位置的值 ✅ 排序过程中索引数组被重新排列 - 最终
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);
}
操作流程分解:
IntStream.range(0, array.length)
✅ 生成0到length-1的整数流(原始索引).boxed()
✅ 将基本类型流转换为包装类型流.sorted(Comparator.comparingInt(i -> array[i]))
✅ 核心排序逻辑:按array
中对应索引位置的值排序.collect(Collectors.toList())
✅ 将排序后的索引收集到List
这种方法更符合函数式编程风格,代码更简洁直观。
5. 结论
我们探讨了在Java中排序数组时保留元素原始索引的两种有效方法:
- 自定义比较器方案:适合需要直接操作数组的场景
- Stream API方案:代码更简洁,适合函数式编程风格
这些方法在需要维护元素位置关系的算法和应用中非常有价值。完整示例代码可在GitHub仓库获取。