Java PriorityQueue自定义对象排序未按compareTo规则生效问题
核心误区
你看到的PriorityQueue调试时的内部元素顺序,不是队列的排序输出顺序。
Java的PriorityQueue底层是用数组实现的二叉堆,它的结构约束仅保证堆顶位置(数组第一个元素)是全局优先级最高/最低的元素,其余位置的元素只满足父子节点的堆性质,不需要全局有序,所以你直接遍历内部数组看到的顺序杂乱是完全正常的,和你的compareTo()逻辑是否生效没有关系。
代码逻辑正确性验证
你写的compareTo()方法逻辑本身符合预期:return this.len - o.len 定义了按单词长度升序排列的小顶堆,长度越短的单词优先级越高,堆顶会始终是当前队列里最短的单词。
正确获取排序结果的方式
不能通过直接查看队列内部存储的元素拿排序结果,必须逐个调用poll()方法弹出元素,弹出的顺序就是严格按定义的优先级排序的顺序。
对你的测试用例leetcode is cool,入队完成后依次弹出的结果为:
- 第一次弹出长度为2的
is(1) - 堆结构调整后,第二次弹出长度为4的
cool(2) - 最后弹出长度为8的
leetcode(0)
拼接后正好是你期望的is cool leetcode。
额外需要修正的细节
- 按照Java编码规范,类名需要大写开头,建议把
word类改名为Word - 当前比较逻辑没有处理同长度单词的排序规则,题目要求同长度单词保留原句中的先后顺序,需要在长度相等时按原始插入序号排序,否则同长度单词的出队顺序是不确定的
- 初始化队列用的
Comparator.naturalOrder()是多余的,不传入比较器时PriorityQueue默认就会使用元素实现的Comparable接口的排序规则 - 题目要求最终结果首单词首字母大写,不要忘记处理这个格式要求
修正后的核心参考代码:
// 类名遵循大写开头的编码规范 public class Word implements Comparable<Word>{ public String theWord; public int len, order; public Word(String w, int order) { this.theWord = w; this.order = order; this.len = w.length(); } @Override public int compareTo(Word o) { // 长度相同按原始出现顺序排序 if(this.len != o.len){ return this.len - o.len; } return this.order - o.order; } } public String arrangeWords(String sentence) { PriorityQueue<Word> minHeap = new PriorityQueue<>(); String[] words = sentence.split(" "); for( int i=0; i<words.length; i++ ) { minHeap.offer( new Word(words[i], i) ); } StringBuilder sb = new StringBuilder(); // 逐个弹出元素拿到排序结果 while (!minHeap.isEmpty()){ sb.append(minHeap.poll().theWord).append(" "); } String res = sb.toString().trim(); // 处理首字母大写的格式要求 return Character.toUpperCase(res.charAt(0)) + res.substring(1); }
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

