我有一堆项目,我存储在最小堆(通过PriorityQueue),我需要有效删除任意项目。我知道在标准的小堆实现中,删除任意元素(假设你知道堆中该元素的位置)需要O(log n)时间,而查找位置是O (N)。所以,基本上,我需要保持一个单独的数据结构,它保存每个项目在堆中的位置。
我或多或少知道如何从头开始实现这一点。但我想知道是否有一种聪明的方法来利用/子类PriorityQueue(它有其他有用的功能)来实现这一目标。
更新:为了澄清,我需要PQ / Min-Heap提供的O(1)peek-min。
答案 0 :(得分:3)
您是否考虑过使用TreeMap。它就像具有PriorityQueue类似功能的Map。
TreeMap不支持O(1)进行删除,但是,它在O(logN)中执行删除操作。远胜于PriorityQueue对O(N)的支持。它还返回集合的头部(min或max元素,具体取决于比较器,就像PriorityQueue一样)。与此同时,它还返回集合的尾部(max或min)。 PriorityQueue不支持尾部功能,因此有时您最终会保留两个队列来同时跟踪头部和尾部。
基于Red-Black树的NavigableMap实现。 该地图是根据其键的自然顺序排序的, 或在地图创建时由比较器提供,具体取决于 使用哪个构造函数。此实现可确保 log(n)containsKey,获取,放置和删除操作的时间成本。 算法是对Cormen,Leiserson和Rivest的算法的改编 算法简介。
红黑树是计算机中的一种自平衡二进制搜索树 科学。二叉树的每个节点都有一个额外的位,该位通常是 解释为节点的颜色(红色或黑色)。这些颜色位用于 确保树在插入和删除过程中保持大致平衡。
Reference to Red-Black Trees algorithm in Introduction to Algorithms
+----------------+-----------------+----------------------------------------------+
| Operation | TreeMap | PriorityQueue |
+----------------+-----------------+----------------------------------------------+
| Insert(Object) | O(logN)[put] | O(logN)[add] |
| Get(Object) | O(logN)[get] | O(N)+ O(N)+O(logN) [contains + remove + add] |
| Delete(Object) | O(logN)[remove] | O(N)[remove] |
| Head |O(logN)[firstKey]| O(1)(peek) |
| Tail | O(logN)(lastKey)| - |
+----------------+-----------------+----------------------------------------------+
答案 1 :(得分:1)
我还需要快速(log N)堆删除以进行超时处理。当队列中有数以万计的元素需要经常删除时,Java 的标准 PriorityQueue 就非常无效了。
这里是我创建的堆实现:fast-delete-heap
所以基本上它维护一个带有元素到堆索引的额外哈希映射,允许快速 O(log N) 删除。不过,它会带来插入速度较慢的代价。