简体   繁体   English

PriorityQueue.poll()调用compareTo()吗?

[英]PriorityQueue.poll() calls compareTo()?

I am implementing a PriorityQueue in my program. 我在程序中实现了PriorityQueue For that I have also implemented compareTo() . 为此,我还实现了compareTo() The compareTo() is being called when I perform add() , which is expected. 当我执行add()add()调用compareTo() ,这是预期的。 But it is also called when I perform poll() . 但是当我执行poll()时也被称为。
I thought that the function of poll() is just to remove the head. 我以为poll()的功能只是去除头部。 Why does it need to call compareTo() ? 为什么需要调用compareTo()

The way a priority queue is implemented is often done with a heap. 实现优先级队列的方式通常是使用堆来完成的。 Part of poll()ing requires restructuring the heap which requires the heap to compare elements... hence compareTo() . poll()ing需要重组堆,这需要堆比较元素……因此compareTo() This is just a guess though (ie I have not dug into the source code to verify my claim). 不过,这只是一个猜测(即,我还没有挖掘源代码来验证我的主张)。

Here's a quick search on how priority queues are implemented using heaps if you are interested: http://pages.cs.wisc.edu/~vernon/cs367/notes/11.PRIORITY-Q.html#imp 如果您感兴趣,可以快速搜索如何使用堆实现优先级队列: http : //pages.cs.wisc.edu/~vernon/cs367/notes/11.PRIORITY-Q.html#imp

Actually just for fun I'll describe how this works in a non-rigorous fashion. 实际上,仅出于娱乐目的,我将以非严格的方式描述其工作方式。 A heap is a tree satisfying the heap property : parents are always less than or equal to their children (min heap) or parents are always at least as large as their children (max heap). 堆是满足堆属性的树:父母总是小于或等于其孩子(最小堆),或者父母总是至少与其孩子一样大(最大堆)。 PriorityQueue is a minheap so poll() removes the root (make sure you understand this). PriorityQueue是一个minheap,因此poll()会删除根(请确保您理解这一点)。 But what happens to the tree if you remove the root? 但是,如果删除根,对树会发生什么? It's no longer a tree... So the way they fix this is by moving the root of the tree to a leaf node (where it can be plucked without destroying the tree/invalidating the heap property), and putting some other node in the root. 它不再是一棵树...因此,他们解决此问题的方法是将树的根移动到叶节点(可以在不破坏树/不使堆属性无效的情况下将其拔出),然后将其他一些节点放入根。 But which node do you put into the root? 但是,您将哪个节点放入根目录? Intuitively you might think they'd put the left or right child of the root (those are "almost as small as the original root"). 凭直觉,您可能会认为它们放置了根的左子或右子(这些子“几乎与原始根一样小”)。 You can do that, but you'd then need to fix the subtree rooted at that child (and the code is ugly). 您可以执行此操作,但随后需要修复根于该子级的子树(并且代码很丑陋)。 Instead they do the same thing (conceptually) but do it slightly differently to make the code nicer. 取而代之的是,它们(在概念上)做相同的事情,但是做得略有不同,以使代码更好。 In particular, they pluck a leaf node and stick it in the root (generally you swap the root and the leaf node to do both steps simultaneously). 特别是,他们拔出一个叶节点并将其粘贴在根中(通常,您交换根和叶节点以同时执行两个步骤)。 However, the heap property is no longer necessarily satisfied (the leaf node we stuck in the root could be quite large!). 但是,不再必须满足heap属性 (我们卡在根中的叶节点可能会很大!)。 To fix this, you "bubble down" the new root until you get it to its correct location. 要解决此问题,您可以“冒泡”新根,直到将其移到正确的位置为止。 Specifically, you compare the new root with the left and right children and keep swapping (if the parent is larger than at least one of the children) until the heap property is satisfied. 具体来说,您将新的根与左,右子级进行比较,并保持交换状态(如果父级大于至少一个子级),直到满足heap属性为止。 Notice that this swapping will indeed lead to a valid heap (you can prove this, but it's intuitive). 注意,这种交换确实会导致有效的堆(您可以证明这一点,但是很直观)。

Everything is in the JavaDoc (emphasis mine): 一切都在JavaDoc中 (重点是我的):

An unbounded priority queue based on a priority heap . 基于优先级堆的无界优先级队列。

And in the source code of poll() you'll find: poll()源代码中,您将找到:

public E poll() {
    //...
    if (s != 0)
        siftDown(0, x);
    return result;
}

Where siftDown() is: siftDown()在哪里:

/**
 * Inserts item x at position k, maintaining heap invariant by
 * demoting x down the tree repeatedly until it is less than or
 * equal to its children or is a leaf.
 * [...]
 */
private void siftDown(int k, E x) {
    if (comparator != null)
        siftDownUsingComparator(k, x);
    else
        siftDownComparable(k, x);
}

The JavaDoc comment on siftDown() is crucial, read it carefully. 关于siftDown()的JavaDoc注释至关重要,请仔细阅读。 Basically the undeerlying implementation of PriorityQueue uses a heap which has to be restructured every time you modify it by polling. 基本上, PriorityQueue的有害实现使用堆,每次通过轮询对其进行修改时,都必须对其进行重组。

Why are you bothered by this? 你为什么为此烦恼? compareTo() should be lightweight, idempotent and side-effect free method, like equals() . compareTo()应该是轻量级,幂等且无副作用的方法,例如equals() You shouldn't put any restrictions on it. 您不应对此施加任何限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM