Priority Queue多条件比较添加RouteInfo对象的Comparator问题排查
问题描述
我有一个存储RouteInfo对象的优先队列(Priority Queue),RouteInfo类定义如下:
public class RouteInfo{ private double totalCost; private double totalLeadTime; private int numberOfLanes; private double totalDistance; // 注:需确保存在对应的getter方法,比如getTotalCost()、getNumberOfLanes()等 }
我的需求是:基于totalCost值将对象加入优先队列,当totalCost相同时比较numberOfLanes,若仍相同则比较totalDistance。我定义了RouteComparator类但似乎不生效,代码如下:
private class RouteComparator implements Comparator<RouteInfo>{ @Override public int compare(RouteInfo routeInfoOne, RouteInfo routeInfoTwo) { if(Objects.equals(routeInfoOne.getTotalCost(),routeInfoTwo.getTotalCost())){ if(routeInfoOne.getNumberOfLanes()==routeInfoTwo.getNumberOfLanes()){ if(Objects.equals(routeInfoOne.getTotalLeadTime(),routeInfoTwo.getTotalLeadTime())){ if(routeInfoOne.getTotalDistance()<routeInfoTwo.getTotalDistance()){ return 1; } else if (routeInfoOne.getTotalDistance()>routeInfoTwo.getTotalDistance()) { return -1; }else{ return 0; } }else if(routeInfoOne.getTotalLeadTime()<routeInfoTwo.getTotalLeadTime()){ return 1; }else if(routeInfoOne.getTotalLeadTime()>routeInfoTwo.getTotalLeadTime()){ return -1; } }else if(routeInfoOne.getNumberOfLanes()<routeInfoTwo.getNumberOfLanes()){ return 1; }else if(routeInfoOne.getNumberOfLanes()>routeInfoTwo.getNumberOfLanes()){ return -1; } }else if (routeInfoOne.getTotalCost() < routeInfoTwo.getTotalCost()) { return 1; }else if (routeInfoOne.getTotalCost() > routeInfoTwo.getTotalCost()) return -1; return 0; } }
请问该Comparator实现是否正确?还需要进行其他操作吗?
问题分析与解决
1. Comparator实现的问题
你的RouteComparator存在几个明显问题:
- 多余判断逻辑:需求中并没有要求比较
totalLeadTime,但代码里额外加入了该字段的比较,会导致排序逻辑和预期不符。 - double类型比较风险:用
Objects.equals()比较double存在精度隐患(比如0.1+0.2不等于0.3),容易出现误判,应该用Double.compare()做标准比较。 - 返回值逻辑混淆:Java的
Comparator中,负整数表示o1排在o2前,正整数表示o1排在o2后。你的代码中,当o1.totalCost < o2.totalCost时返回1,意味着更小的totalCost会被排在后面,若需求是优先出队最小totalCost的元素,这里逻辑完全搞反了。
2. 正确的Comparator实现
假设你需要升序排序(优先队列头部是totalCost最小的元素,totalCost相同则numberOfLanes小的优先,再相同则totalDistance小的优先),正确实现如下:
private class RouteComparator implements Comparator<RouteInfo> { @Override public int compare(RouteInfo o1, RouteInfo o2) { // 先比较totalCost int costCompare = Double.compare(o1.getTotalCost(), o2.getTotalCost()); if (costCompare != 0) { return costCompare; } // totalCost相同,比较numberOfLanes int lanesCompare = Integer.compare(o1.getNumberOfLanes(), o2.getNumberOfLanes()); if (lanesCompare != 0) { return lanesCompare; } // numberOfLanes相同,比较totalDistance return Double.compare(o1.getTotalDistance(), o2.getTotalDistance()); } }
如果需要降序排序(优先队列头部是totalCost最大的元素),只需在每个比较结果前加负号,比如:
return -Double.compare(o1.getTotalCost(), o2.getTotalCost());
3. 必须的额外操作
- 补全RouteInfo的getter方法:确保
RouteInfo类存在getTotalCost()、getNumberOfLanes()、getTotalDistance()这些getter方法,否则Comparator无法获取字段值。 - 初始化PriorityQueue时传入Comparator:Java默认的PriorityQueue依赖元素的自然排序(需实现Comparable接口),必须显式传入自定义的
RouteComparator实例,示例代码:
PriorityQueue<RouteInfo> routeQueue = new PriorityQueue<>(new RouteComparator());
4. 注意事项
- 永远不要用
==或Objects.equals()直接比较double类型,优先使用Double.compare()避免精度问题。 - 确保Comparator逻辑满足传递性:即如果
a > b且b > c,则a > c,否则优先队列的行为会不可预测。
内容的提问来源于stack exchange,提问作者Ragin P M
相关产品推荐
相关产品推荐

