You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 14:33:36