是否存在带有提取的优先级队列?


46

有很多数据结构实现了优先级队列接口:

  • 插入:将元素插入结构
  • Get-Min:返回结构中的最小元素
  • Extract-Min:删除结构中的最小元素

实现此接口的常见数据结构是(min)

通常,这些操作的(摊销)运行时间为:

  • 插入:(有时)Olog n O(1)O(logn)
  • Get-Min:O(1)
  • 提取最小值:O(logn)

例如,斐波那契堆可达到这些运行时间。现在,我的问题是:

是否存在具有以下(摊销)运行时间的数据结构?

  • 插入:O(logn)
  • Get-Min:O(1)
  • 提取最小值:O(1)

如果我们可以在给定排序输入的情况下在时间内构造这样的结构,那么我们可以例如在比使用“通常”优先级队列的路口快得多。o nO(n)o(nlogn)


认为使用平衡的BST,在进行Extract-Min可行时不会重新平衡。或跳过列表。
svick

@svick:跳过列表是随机的,这不是我想要的。如果您可以使用BST做到这一点,那就太好了,但是我认为您必须进行某种平衡。
亚历克斯(Alex)10 Brink 2012年

附带说明:这是一个种子问题,我知道答案,但是很高兴看到它不是那么容易解决。如果有人知道答案,请不要犹豫:)
亚历克斯·十·布林克2012年

如果您接受摊销的更新时间,则可以保留标准堆结构,并且仅对分析进行较小的修改。请参阅下面的答案。
2012年

Answers:


27

我们的想法是使用线程 展开树。除了Wikipedia文章外,我们还将对树进行线程化,以便每个节点next在有序遍历中都有一个指向其后继节点的指针。我们还持有一个指向start树中最小元素的指针。

很容易看出,在(最坏的情况下)时间可以提取最小的元素:只需跟随指针,删除最小值,然后将指针更改为最小值。最小的孩子永远不能生一个孩子。如果它有一个合适的孩子,我们将其放在树中最小的位置。我们执行splay操作,splay树通常会执行。 结果是搜索树仍然保持合理的平衡:因为我们只删除了左侧侧面的节点,所以我们知道当(受影响的子树中)的节点数由于删除而下降到原始数的一半时,(树的高度减少一。O(1)startnext

可以在摊销时间内插入;之字形操作(以及其他操作)也将很好地重新平衡树。O(logn)

这充其量只是一个粗略的草图。值得称赞的是F.温伯格(F. Weinberg),他和我一起为这个问题感到困惑,而我们的顾问M. Nebel(M. Nebel)提到了八角树,这是我们没有尝试过的唯一的树变种。


2
如果您不使用extractMin进行分析,对我来说还不清楚如何使摊销分析生效。你能给个提示吗?
jbapple 2012年

我们尚未详细说明。想法是,一系列min-min操作不会使树不平衡,因此不需要展开,并且正常分析应该适用于插入。
拉斐尔

9
小心!八卦树不一定是平衡的。还没有在很长一段时间被访问节点可以树深。为了使分析顺利进行,您必须就用于分析八字的潜在功能进行争论。
JeffE 2012年

20
  • 插入:O(logn)
  • Get-Min:O(1)
  • 提取最小值:O(1)

摊销时间

优先级队列的简单实现(例如,任何平衡的BST或标准二进制min-heap)都可以通过简单地收取要插入的Extract-Min的开销并维护指向最小元素的指针来实现这些(摊销)运行时间。例如,您可能具有的潜在功能。然后插入一个新元素将使电位增加,因此插入的摊销成本仍为,但是Extract-Min()将电位减少了,并且因此摊销成本仅为。O log n O log n Ω log n O 1 cnlognO(logn)O(logn)Ω(logn)O(1)

最差的情况

您可以使用文献中现有的数据结构:手指搜索树,只需维护指向最小元素的指针即可。有关概述,请参见本次调查;Levcopoulos和Overmars于1988年发表的论文中提供了可满足您需求的可实施版本。


1
真是偷偷摸摸。您说得对,我想我应该要求更强有力的措施才能排除这一点。好主意:)
亚历克斯十Brink

@AlextenBrink您可能需要最坏情况下的删除。(这似乎是其他一些答案所要解决的问题)我在答案中添加了一段以解决这种情况。O(1)

14

2-4棵树在已知位置已摊销修改。也就是说,如果您有一个指向树中某个位置的指针,则可以在摊销时间内在其中删除或添加一个元素。O 1 O(1)O(1)

因此,您可以仅将指针指向2-4棵树中的最小元素和根节点。插入应通过根节点。在deleteMin之后将指针更新为最小值很简单,而deleteMins为(分期)时间。O(1)

一个有趣的旁注:红黑树只是看2-4棵树的一种方式。C ++ 98标准的设计者希望库实现者提供基于红黑树的容器,并且该标准指定在已知位置(称为“迭代器”插入和删除应为摊销时间。 )。但是,对于红黑树来说,这实际上要比2-4棵树复杂得多,因为它需要懒惰地标记需要重新着色的节点。据我所知,没有C ++ 98标准库的实现满足该特定要求。O(1)


8

根据要求,这是我提出问题后发现的结构:

基本思想是使用线程化的 替罪羊树以及指向最小值的指针(也可以使用最大值的指针)。一种更简单的线程替代方法是在每个节点中维护前任和后继指针(这是等效的,更简单,但开销更大)。我来称呼它为替罪羊,只是为了给它起个名字。

仅此基本结构即可为您提供以下操作:

  • 搜索:给定一个键,在时间返回一个指向相应节点的指针。O(logn)
  • 插入:给定键,将键插入结构,并在时间返回指向该节点的指针。O(logn)
  • 前任/前任:给定一个指针,将在时间返回后任或前任。O(1)
  • Get-Min / Max:将指针返回到最小值或最大值。

在替罪羊树的分析中,删除的平衡开销被分析为,但分析实际上给出了的平衡开销(在本文中被忽略了)因为他们还计算时间来找到要删除的节点)。因此,如果我们有一个指向节点的指针,我们可以在固定时间内删除它(您可以在时间在线程二进制搜索树中完成此操作),并与的平衡开销,这会给时间删除:O1 Olog n O1 O1 O1 O(logn)O(1)O(logn)O(1)O(1)O(1)

  • 删除:给定一个指针,将在时间内删除该节点。O(1)

结合这个:

  • Extract-Min / Max:在时间中删除最小/最大节点。O(1)

您可以使用指针做更多的事情:例如,维护指向中位数或其他阶次统计信息的指针并不难,因此,如果需要,可以保持一定数量的此类指针。

其他一些事情:

  • 构造:按排序顺序给定键,在时间内构建一个替罪羊堆。On nO(n)
  • 平衡:平衡该树,使其在时间内形成一个完美平衡的二叉搜索树(减少搜索的开销(通过使用,您可以比本文建议的速度快一个常数因子)前导/后继指针)。O(n)

最后,我很确定您可以支持这些操作,但是在确定这一点之前,我需要多考虑一下这些内容:

  • Insert-New-Min / Max:给定一个小于或大于结构中现有键的键,将其插入结构,并在时间返回指向该节点的指针。O(1)

关键见解是替罪羊树可以确保您删除任何节点而无需重新平衡,即使您删除许多节点,从长远来看也不会影响其他操作的性能。
拉斐尔

我知道在替罪羊树中进行删除的两种方法。镜像插入的一种方式是摊销时间。我听说过的另一种方法是使用全局重建,并分摊,但在这种情况下我不知道如何维护线程。想象一下,将一个新密钥插入到树的一部分中,该部分是所有已删除的密钥尚未删除。如何在时间中找到要插入的密钥的前身?Ô 1 ø LG Ñ O(lgn)O(1)O(lgn)
jbapple 2012年

2
@jbapple:关于替罪羊树在时间内如何进行删除有两种变体。一种是保留该节点,将其标记为已删除,然后通过全局重建来删除所有这些已删除的节点,另一种是真正删除该节点。第一个更易于分析(也为您提供了第二个的界限,这就是通常被解释的原因),但是第二个是我所追求的:您可以在原始二进制搜索树中以时间删除如果您可以在时间内执行前辈/后继查询,并且在时间内进行平衡就可以为您提供余下的界限。O 1 O 1 O 1 O(1)O(1)O(1)O(1)
亚历克斯十布林克

啊,我现在明白了。
jbapple 2012年

2

软堆是对二项式队列的微妙修改。数据结构近似为错误参数。它支持插入,删除,融合和查找。除需要时间的insert之外,每个操作的摊销复杂度为。软堆的新颖之处在于超越了基于比较的模型中堆的复杂性的对数界限。为了打破信息理论的障碍,通过人为地提高一些键的值来减少数据结构的熵。这称为破坏密钥。数据结构完全基于指针(无数组或数值假设),并且对于任何值都是最佳的O 1 日志1 / ϵ ϵO(1)log(1/ϵ)ϵ 在基于比较的模型中。

ϵn

对于原始,清晰且写得很好的论文,请参见Bernard Chazelle,《软堆:具有最佳错误率的近似优先级队列》,ACM杂志,47(6),第1012-1027页,2000年。有关自SODA'09声称更简单,更直观的替代实现和分析,请参阅Kaplan H.&Zwick U。,《 Chazelle软堆的更简单实现和分析》,2009年


尽管数据结构非常有趣,但是软堆并不精确:findmin可能返回的值不是最小值,而仅仅是一个近似最小值。无论如何,感谢您的链接:)
亚历克斯十布林克

1
@AlextenBrink:数据结构(就像许多概率算法一样)的要点是,您可以使用近似数据结构来获取确切答案。实际上,软堆的近似性质并未阻止它在最小生成树的唯一已知线性时间算法中使用。
热雷米

2

好的,终于让您找到了想要的复杂性,而最好的是,我在文献中发现了这一点:

最坏情况的复杂性

O(1)

O(1)

O(1)

O(log n)

参考

[3]O(1)O(log n)O(n)

Brodal,GerthStølting。“可快速熔化的优先队列”。在第四届算法和数据结构国际研讨会论文集,282–290。WADS '95。英国伦敦,英国:Springer-Verlag,1995年。

[3]Dietz,Paul F和Rajeev Raman。“恒定更新时间手指搜索树”。信息处理信函52号。3(1994):147 – 154。

虽然这使用计算RAM 模型

我们的数据结构使用具有单位成本度量和对数字长的随机访问机器(RAM)模型;

最近,已经给出了计算解决方案的Pointer-Machine模型[1]

[1]Brodal,GerthStølting,George Lagogiannis,Christos Makris,Athanasios Tsakalidis和Kostas Tsichlas。“指针机器中的最佳手指搜索树”。J.计算机 Syst。科学 67号 2(2003年9月):381-418。


2

通过维护两个数据结构来解决此问题:数组和二叉树。

Ω(lognloglogn)Ω(logn)

O(logn)O(logn)

nullO(logn)

O(1)O(1)

O(logn)O(1)delete_at(idx)


1 Patrascu,Mihai和Erik D. Demaine。“ Cell-Probe模型中的对数下界。” SIAM J. Comput。35,没有 4(2006年4月):932-963。doi:10.1137 / S0097539705447256。


1
O(logn)

“将二进制搜索树放入数组中”是什么意思?
jbapple 2012年

@AT:我分享jbapple的观点。
拉斐尔

Ω(k)kO(1)

您在更新中解释了如何在恒定时间内实现轮换,但此更新不适用于数组。这个答案仍然不正确。您参考的Tarjan论文是关于存储有节点和指针的树的。
jbapple

-2

O(1)O(log log n)

参见2007年的论文:Mikkel Thorup的优先级队列与排序之间的等效性

O(n log log n)


尽管您链接的论文很有趣,但是它们提出的优先级队列并没有固定的时间删除时间(如果我正确地阅读了摘要),因此不是我要的。
亚历克斯(Alex)10 Brink 2012年

-2

分析

o(n log log n)

o(log log n)

O(1)

O(n)

O(1)

O(1)

实作

  1. O(1)
  2. O(6)O(1)
  3. k±
    ((k>nsize1)(k<n0)((k<ni)(k>ni+1)))
    o(log log n)

[1]:Andersson,Arne和Christer Mattsson。“在O(log log n)时间中进行动态插值搜索”。在Andrzej Lingas,Rolf Karlsson和Svante Carlsson编辑的《自动机,语言和程序设计》中,700:15–27。计算机科学讲义。Springer Berlin / Heidelberg,1993年。http://dx.doi.org/10.1007/3-540-56939-1_58


2
好吧,插入时间远远超出了预期。
拉斐尔

nsize1n0nini+1

阅读您链接的论文的摘要,似乎这些界限是特定分布的输入的预期界限,因此,这不是我要查找的内容:我希望我在任何输入中提及的界限。
亚历克斯十布林克

O(log n)

@AT对数二进制搜索需要随机访问。实现的基础列表是什么?您应该为自己声称的范围辩护。另外,“列表中的位置”是模糊的-什么位置以及符号所指的是什么?并非所有人都可以访问您链接的论文。请尝试使您的答案(更多)自成一体,至少要总结事实。在这一点上,我认为您的答案不正确。
Juho 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.