PriorityQueue是Java不按自定义比较器降序

时间:2017-07-16 11:12:09

标签: java priority-queue comparator

我正在实施样本订单簿(在Exchange域中),并且我正在使用Java中的PriorityQueue实现买入和卖出方。

买方应该是下行而卖方应该是上升

PriorityQueue<ArrayList<Order>> bookSide;

每一方都包含价格点,每个点都有一个订单列表。

Buy/Sell Side

我的买方工作正常。

这是我的卖方。我希望这是下降的。

sellSide = new PriorityQueue<ArrayList<Order>>(new Comparator<ArrayList<Order>>() {

    @Override
    public int compare(ArrayList<Order> arg0, ArrayList<Order> arg1) {
        // below two conditions are highly unlikely to happen
        // as the the elements are added to the list before the list is
        // added to the queue.
        if (arg0.size() == 0) {
            return -1;
        }
        if (arg1.size() == 0) {
            return -1;
        }
        // all the elements in a list have a similar price
        Order o1 = arg0.get(0); 
        Order o2 = arg1.get(0);
        int r = (int) (o1.getPrice() - o2.getPrice());
        return  r;

    }

});

我添加了100,100,101和99。

当添加101时,它正确地将101添加到100以下(100个列表)。但是当我添加99时,它会破坏顺序并变为99,101,100。

我不知道出了什么问题。

请帮帮我。

修改

这就是我将这些元素添加到列表中的方法。 pricelong

ArrayList<Order> pricePoint = sidePoints.get(price);
if (pricePoint == null) {
    pricePoint = new ArrayList<>();
    pricePoint.add(order); // I want the list to be non-empty when adding to queue
    bookSide.add(pricePoint);
} else {
    pricePoint.add(order);
}

1 个答案:

答案 0 :(得分:3)

似乎对PriorityQueue的工作方式存在误解。 让我们试着澄清一下。

  

但是当我添加99时,它会破坏顺序并变为99,101,100。

首先,来自Javadoc of PriorityQueue的重要提醒:

  

基于优先级堆的无界优先级队列。

这里的关键术语是 heap 。 在堆中,元素不按顺序排序。 堆是树状结构, 其中每个节点与下面下的每个其他节点相比一致排序。 换一种说法, 对于同一级别的节点排序没有任何保证。

按升序排列的堆(最小堆)将保证顶部元素最小。 弹出顶部元素后, 下一个顶部元素将是剩余元素中最小的元素。 等等。

如果您需要已排序元素的列表, 你必须通过逐个从堆中弹出来构建它。 或者, 你只能用一个清单, 并使用Collections.sort对其进行排序。

顺便说一下, 正如其他人在评论中所指出的, compare方法的实现违反了Comparator接口的约定: 当ab中只有一个为空时, compare(a, b)compare(b, a)都返回-1, 这意味着a < bb < a, 这打破了逻辑。

修复很容易,我还简化了其余的实现:

@Override
public int compare(ArrayList<Order> arg0, ArrayList<Order> arg1) {
  if (arg0.isEmpty()) {
    return -1;
  }
  if (arg1.isEmpty()) {
    return 1;
  }

  return Integer.compare(arg0.get(0).getPrice(), arg1.get(0).getPrice());
}