【问题标题】:Efficient nested priority queue高效的嵌套优先级队列
【发布时间】:2017-01-20 03:42:42
【问题描述】:

我正在寻找一种本质上是嵌套优先级队列的数据结构/算法(非多线程)。那就是:

  1. 下一个要采用的元素是具有最高优先级的元素。
  2. 一个元素既可以是一个具有优先级的简单元素,也可以是另一个优先级队列(尽管对于我的目的来说,一级嵌套的限制是可以的)。无论嵌套级别如何,队列/子队列/子子队列/等中具有最高优先级的元素都是下一个选择的元素。
  3. 可以在任何级别添加或删除元素,但简单的节点永远不会变成子队列(反之亦然)。
  4. 简单元素的优先级在插入后不会改变。

我还没有想出任何高效/优雅的东西,谷歌搜索也没有发现任何东西。

【问题讨论】:

    标签: algorithm data-structures priority-queue


    【解决方案1】:

    我实际上并没有构建这个,但我对这个想法做了一些非常广泛的分析,看起来它应该可以工作。我称之为队列队列。我从未构建它的原因是因为我构建它的项目在我需要队列之前被取消了。

    首先,我决定将“简单元素”改为包含单个元素的优先级队列。不必管理两种不同类型的元素简化了设计,分析表明它不会对性能产生任何重大影响。

    由于子队列的优先级可以在添加新项目或从中删除项目时更改,因此我选择对主队列和子队列使用Pairing heap。当您必须进行大量优先级更改时,配对堆比二叉堆执行得更好。二叉堆的问题是,如果你想改变一个项目的优先级,你必须先找到这个项目。在二叉堆中,这是一个 O(n) 操作。在配对堆中,优先级更改的摊销成本为 O(log n),因为您已经拥有对节点的引用。

    所以想法是,如果您要添加一个新的子队列,您只需将其添加到主队列中,它就会被放置在适当的位置。如果要更新子队列,则添加或删除项目(在子队列上为 O(log n)),然后调整子队列在主队列中的位置(即 O(log n ) 在主队列上)。

    我的所有分析都表明这应该可以很好地工作,尽管我仍然不确定它与多个线程一起工作的效果如何。我认为我很清楚如何同步访问,而不是在每次插入和删除时阻塞整个队列,除了很短的时间。我想我会知道我是否曾经建造过它。 可能可以创建一个无锁并发配对堆。

    我选择了配对堆,因为它在重新排序键方面有更好的性能,还因为它比斐波那契堆或其他许多堆更容易实现,而且虽然它的渐近性能比斐波那契堆慢,但它的真实世界性能要好得多。对我来说唯一的缺点是配对堆比等效的二进制堆占用更多的内存。这是旧的时间/空间权衡。

    另一种选择是实现skip list 优先级队列,该队列对于插入和更改优先级也具有 O(log n) 性能。而且我已经看到了无锁并发跳过列表实现。在 C 中实现一个有效的跳过列表并不困难,因为它可以很好地处理可变的记录大小。在 C# 和其他不允许您构建可变长度结构的语言中,跳过列表可能会占用大量内存。

    正如我所说,我从未真正构建过这个东西,但我所有的研究和设计笔记都告诉我,它应该相当容易构建并且性能应该相当好。

    【讨论】:

    • 有趣的是,我一直在处理二进制堆的这种限制——必要时——通过维护其子堆的索引属性。每当堆移动项目时,它都会更新它们的索引。这使得 O(1) 查找 (item.HeapIndex) 和 O(1) 包含 (items[item.HeapIndex] == item) 不会有意义地改变任何其他操作的性能特征。
    猜你喜欢
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 2023-03-20
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多