Java中非负数排序保留负数位置:自定义Comparator失效问题及方案探讨
Java整数列表排序:仅排序非负数且保留负数位置的问题分析
问题背景
需求是对整数列表排序时,仅对非负数进行升序排序,负数的索引位置保持不变。相关输入、输出及尝试代码如下:
- 输入列表:
40,20,-2,0,-5,25,-3,44,24,29,38 - 期望输出列表:
0,20,-2,24,-5,25,-3,29,38,40,44 - 尝试的排序代码:
list.sort((a,b)->(a<0||b<0)?0:a-b);
- 实际输出列表:
0,20,25,40,-2,-5,-3,24,29,38,44
原Comparator的问题
这段Comparator的核心错误在于:当比较的两个元素中存在负数时返回0,这会让排序算法认为这两个元素“等价”。而Java的sort方法基于TimSort实现,会根据这个等价判断随意调整元素的相对位置,直接导致两个问题:
- 负数的位置被打乱:比如原列表中位于索引2的
-2,会被和前面的非负数交换位置,最终跑到索引4的位置。 - 非负数排序不符合预期:被负数隔开的非负数,在和负数比较时返回
0,排序算法无法识别它们的原始位置关联,导致非负数没有被放回原本的非负数索引位。
能否用Comparator解决该需求?
不能。Comparator的设计逻辑是基于元素的值进行比较,无法获取元素在原列表中的索引信息。而本需求的核心是要在原列表的非负数索引位置上填充排序后的非负数,这个逻辑依赖元素的原始位置,单纯通过Comparator无法实现。
正确的实现思路
正确的做法是拆分步骤:先提取所有非负数并排序,再将排序后的非负数依次放回原列表的非负数位置:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class SortNonNegatives { public static void main(String[] args) { List<Integer> list = new ArrayList<>(Arrays.asList(40,20,-2,0,-5,25,-3,44,24,29,38)); // 提取所有非负数并升序排序 List<Integer> sortedNonNegatives = list.stream() .filter(num -> num >= 0) .sorted() .collect(Collectors.toList()); // 将排序后的非负数放回原列表的对应位置 int nonNegIdx = 0; for (int i = 0; i < list.size(); i++) { if (list.get(i) >= 0) { list.set(i, sortedNonNegatives.get(nonNegIdx++)); } } System.out.println(list); // 输出:[0, 20, -2, 24, -5, 25, -3, 29, 38, 40, 44] } }
内容的提问来源于stack exchange,提问作者Arjun
相关产品推荐
相关产品推荐

