【问题标题】:.NET Dictionary / Hashtable That Also Maintains Sort?.NET 字典/哈希表也维护排序?
【发布时间】:2013-09-16 03:26:14
【问题描述】:

以下是要求:

  1. 存储具有多个属性的对象,包括唯一 ID 以及用于排序的优先级整数。
  2. 优先级将有重复值。
  3. 通过对象的 ID(即字典/哈希表键)检索/检查对象是否存在是 O(1)。
  4. 按优先级检索“前 10 项”必须尽可能快。我的假设是这意味着必须有一个单独的 List / LinkedList 来保存对字典/哈希表中项目的引用。如果是这样,则无论何时添加或删除项目,或项目的优先级值发生变化,都必须维护此 List / LinkedList。
  5. 在添加/删除项目或更改项目的优先级时重新排序项目的速度尽可能快。

你会使用什么数据结构? .NET 中是否已经存在一个?还是应该定制?我倾向于后者。

【问题讨论】:

  • 我可以像男人一样投反对票。但至少告诉我为什么。 :o)

标签: .net list sorting dictionary hashtable


【解决方案1】:

SortedList 为您提供顺序访问和 O(log n) 检索,这是您使用提供的 .NET 集合所能做的最好的事情。

当我需要这样做时,我结合了优先队列和字典。它看起来像:

var myqueue = new PriorityQueue<DataType>();
var myDictionary = new Dictionary<KeyType, PriorityQueueNode<DataType>>();

每当我插入一个项目时,我都会将它插入到队列中,该队列返回一个PriorityQueueNode。我把它插入字典了。

这给了我 O(1) 检索和 O(log n) 插入。如果您使用 pairing heap 而不是我使用的二进制堆优先级队列,您可以获得分期 O(1) 插入。

检索前 k 个项目是 O(n log k),其中 n 是优先级队列中的项目数。我为此使用了堆选择。我在When theory meets practice 中写了一些关于堆选择的内容。考虑到这些项目已经在堆中,您应该能够使用基于An Optimal Algorithm for Selection in a Min-Heap 的技术在 O(k) 中完成它。我认为有可能,但我没有这样做。

我有一个基于堆的优先级队列可能会为您解决问题。来源是http://mischel.com/pubs/priqueue.zip。不幸的是,我写的关于它的文章不再在线提供。但是,如果您给我发电子邮件(jim AT mischel.com)并提及此帖子,我会看看我是否可以挖掘它。

不过,我不再拥有组合字典/优先级队列的代码。对不起。

cmets 中的问题解答

您想要优先级队列还是列表/链表实际上取决于您如何使用它以及集合中有多少项目。如果使用线性列表,添加和更改优先级为 O(n)。如果您按键删除,则删除时间为 O(1)。按优先级删除是 O(n),因为您必须先找到该项目才能将其删除。但是找到前 k 个项目是微不足道的:你拿前 k 个项目。

在二叉堆优先级队列中,插入、删除和更改优先级为 O(log n)。获取前 k 个项目是 O(k),但实际上比线性列表慢。尽管如果您知道它始终是您想要的前 10 名,您可以在单独的列表中找到并缓存它们。这样,您可以在大多数情况下快速归还它们。每当您添加、删除或更改优先级时,您都会设置一个脏标志,以便您知道下次有人要求时重新生成前 10 个列表。

pairing heap 很可能就是您正在寻找的。它确实在 O(1) 摊销时间内添加和删除。更改优先级并不算太糟糕(请参阅链接的 Wikipedia 文章和原始论文 [上面链接])。删除是 O(log n)。找到前 10 名的最坏情况是 O(n log k),但是您可以再次缓存这些项目,并且仅在堆更改时才重新生成前 10 名。如果 k 是一个常数或最大 k 是项目总数的一小部分,则缓存的想法最有效。

您可以看看C5 Generic Collection Library,它有几个优先级队列实现。我没用过,但听说过它的好东西。

这实际上归结为集合中有多少项目以及更改频率与前 10 名的请求之间的关系。在一个真正杀死你的线性列表。而且由于您可以轻松地缓存前 10 个列表并根据需要重新创建它,因此当集合大小增加时,优先级队列对其他操作的较低成本非常有吸引力。

想一想,考虑到您的操作组合,SortedList 可能是您想要的。获得前 10 项的速度非常快。它很容易使用。为什么不制作一个原型,看看它是否能提供足够好的性能?

【讨论】:

  • 很可能是一个愚蠢的问题。如果我希望经常阅读优先级的“前 10 项”,有时修改随机项的优先级值,并偶尔添加/删除项目,队列是最好的补充结构吗?它是否比每次修改/添加/删除时简单排序的 List 或 LinkedList 更可取?尤其是因为在阅读时,我不想将内容从队列中弹出,而是希望它们保持存储状态?
猜你喜欢
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
  • 2012-08-23
  • 2014-01-04
相关资源
最近更新 更多