优先级队列/堆更新
一旦 PriorityQueue 中对象的优先级发生变化,Java 是否有一种简单的方法来重新评估堆? 我在 Javadoc 中找不到任何迹象,但必须有一种方法可以做到这一点,对吗? 我目前正在删除该对象,然后重新添加它,但这显然比在堆上运行更新慢。
Does Java have an easy way to reevaluate a heap once the priority of an object in a PriorityQueue has changed? I can't find any sign of it in Javadoc
, but there has to be a way to do it somehow, right? I'm currently removing the object then re-adding it but that's obviously slower than running update on the heap.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您可能需要自己实现这样的堆。 您需要一些处理该项目在堆中的位置的句柄,以及一些在其优先级发生更改时向上或向下推送该项目的方法。
几年前,我写了这样的一堆作为学校作业的一部分。 向上或向下推动一个项目是一个 O(log N) 的操作。 我将以下代码发布为公共领域,因此您可以以任何方式使用它。 (您可能希望改进此类,以便排序顺序将依赖于 Java 的 Comparator 和 Comparable 接口,而不是抽象的 isGreaterOrEqual 方法,并且还将使该类使用泛型。)
You might need to implement such a heap yourself. You need to have some handle to the position of the item in the heap, and some methods to push the item up or down when its priority has changed.
Some years ago I wrote such a heap as part of a school work. Pushing an item up or down is an O(log N) operation. I release the following code as public domain, so you may use it in any way you please. (You might want to improve this class so that instead of the abstract isGreaterOrEqual method the sort order would rely on Java's Comparator and Comparable interfaces, and also would make the class use generics.)
PriorityQueue 具有对整个堆重新排序的
heapify
方法、将更高优先级的元素提升到堆上的fixUp
方法以及fixDown
code> 方法,它将较低优先级的元素压入堆中。 不幸的是,所有这些方法都是私有的,因此您无法使用它们。我会考虑使用观察者模式,以便包含的元素可以告诉队列其优先级已更改,然后队列可以执行诸如
fixUp
或fixDown
之类的操作,具体取决于如果优先级分别增加或减少。PriorityQueue has the
heapify
method which re-sorts the entire heap, thefixUp
method, which promotes an element of higher priority up the heap, and thefixDown
method, which pushes an element of lower priority down the heap. Unfortunately, all of these methods are private, so you can't use them.I'd consider using the Observer pattern so that a contained element can tell the Queue that its priority has changed, and the Queue can then do something like
fixUp
orfixDown
depending on if the priority increased or decreased respectively.标准接口不提供更新功能。 您已使用实现此功能的自定义类型。
你是对的; 尽管当您删除并替换堆顶部时,使用堆的算法的大 O 复杂性不会改变,但它们的实际运行时间几乎会增加一倍。 我希望看到对
peek()
和update()
堆使用方式的更好的内置支持。The standard interfaces don't provide an update capability. You have use a custom type that implements this.
And you're right; although the big-O complexity of algorithms that use a heap doesn't change when you remove and replace the top of the heap, their actual run time can nearly double. I'd like to see better built-in support for a
peek()
andupdate()
style of heap usage.这是正确的。 Java 的
PriorityQueue
没有提供更新优先级的方法,而且删除似乎需要线性时间,因为它不像Map
那样将对象存储为键。 事实上它多次接受同一个对象。我还想让PQ提供更新操作。 这是使用泛型的示例代码。 任何可比较的类都可以与它一起使用。
在这里,在更新时,我只是增加优先级(对于我的实现)并且它使用 MaxHeap,所以我正在做 bubbleUp。 人们可能需要根据需求进行堆化。
That's right.
PriorityQueue
of Java does not offer a method to update priority and it seems that deletion is taking linear time since it does not store objects as keys, asMap
does. It in fact accepts same object multiple times.I also wanted to make PQ offering update operation. Here is the sample code using generics. Any class that is Comparable can be used with it.
Here while updating, I am only increasing the priority (for my implementation) and it is using MaxHeap, so I am doing bubbleUp. One may need to heapify based on requirement.
根据数据结构的实现,可能没有更快的方法。 大多数 PQ/堆算法不提供更新功能。 Java 实现可能没有任何不同。 请注意,尽管删除/插入会使代码变慢,但它不太可能导致代码具有不同的运行时复杂性。
编辑:看看这个帖子:允许高效优先级更新的优先级队列?
Depending on the implementation of the data structure, there may not be a faster way. Most PQ/heap algorithms do not provide an update function. The Java implementation may not be any different. Notice that though a remove/insert makes the code slower, it is unlikely to result in code with a different runtime complexity.
Edit: have a look at this thread: A priority queue which allows efficient priority update?
不幸的是,JDK 的优先级队列不提供更新。
Robert Sedgewick 和 Kevin Wayne 因其在普林斯顿大学的算法课程而闻名,他们还撰写了算法。
在这本优秀的书中,他们提供了自己的数据结构实现,包括可更新的优先级队列,例如 IndexMinPQ.java
根据 GPLv3 许可。
Unfortunately, JDK's Priority Queue doesn't provide updates.
Robert Sedgewick and Kevin Wayne are well known for their algorithms courses in Princeton, and they also wrote Algorithms.
Inside this excellent book, they provide their own implementations for data structures, including updateable priority queues, such as IndexMinPQ.java
Licensed under GPLv3.
您需要自己实施。 但你不必花哨。 在 Java 的
remove(Object)
实现中,删除堆项的实际耗时是indexOf()
,因为它必须迭代整个列表才能找到该项的索引。特定对象。 如果你实现自己的数据结构,你可以告诉每个对象在数组中的位置,即使你的实现并不奇特,它也会优于 Java 的,因为每个对象都会知道它在数组中的位置。存储这些信息时,您只需执行经典的删除和添加新项目即可,这样您就可以远远击败 Java。
更新例程仅在特定索引上调用 heapify。 它节省了 heapify 调用和一些常量操作。 这里的大部分优化是 Java 的实际
PriorityQueue
无法存储索引。 因此,在该数据结构中,remove(Object)
实际上是一个相当昂贵的操作。 因为您必须在列表中找到该对象。 这个特殊的类将PriorityQueue
所花费的时间减少到几乎为零。 尽管它要求您对放入堆中的项目实施Heap.Indexed
。You need to implement it yourself. But you don't have to get fancy. The actual massive timesuck of removing the heap item in Java's implementation of
remove(Object)
is actuallyindexOf()
since it has to iterate the entire list to find the index of the particular object. If you implement your own datastructure you can tell each object the position in the array and even if your implementation isn't anything fancy it'll outperform Java's since each object would know where its located in the array.Storing that information you can do just the classic remove and add the new item and you'll beat Java by a lot.
The update routine just calls heapify on the particular index. It saves a heapify call, and some constant operations. The bulk of the optimization here is that Java's actual
PriorityQueue
can't store the index. Soremove(Object)
is actually a pretty expensive operation within that datastructure. As you're going to have to locate that Object in the list. This particular class reduces the time taken byPriorityQueue
to nearly nothing. Though it requires that you implementHeap.Indexed
on the items you put in the heap.