.NET Dictionary / Hashtable还维护排序?

时间:2013-09-11 22:39:20

标签: .net list sorting dictionary hashtable

以下是要求:

  1. 存储具有多个属性的对象,包括除用于排序的优先级整数之外的唯一ID。
  2. 优先级会有重复值。
  3. 通过其ID(即Dictionary / Hashtable键)检索/检查对象是否为O(1)。
  4. 按优先级检索“前10项”必须尽可能快。我的假设是这意味着必须有一个单独的List / LinkedList来保持对字典/哈希表中的项的引用。如果是这样,只要添加或删除项目,或者项目的优先级值发生变化,就必须维护此List / LinkedList。
  5. 在添加/删除项目或更改项目的优先级时重新排序项目的速度尽可能快。
  6. 您将使用什么数据结构? .NET中是否已存在?还是应该定制?我倾向于后者。

1 个答案:

答案 0 :(得分:2)

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)并提及这个帖子,我会看看我是否可以把它挖出来。

但我不再拥有组合字典/优先级队列的代码。遗憾。

评论中的问题解答

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

在二进制堆优先级队列中,插入,删除和更改优先级为O(log n)。获得前k项是O(k),但实际上比线性列表慢。虽然如果你知道它总是你想要的前10名,你可以找到并将它们缓存在一个单独的列表中。这样你大部分时间都可以快速返回。每当添加,删除或更改优先级时,您都会设置一个脏标志,以便您知道在下次有人要求时重新生成前10个列表。

pairing heap很可能就是你想要的。它确实在O(1)摊销时间内添加和删除。改变优先级也不算太差(参见链接的维基百科文章和原始论文[上面链接])。删除是O(log n)。找到前10名的最坏情况是O(n log k),但是你可以再次缓存这些项目,只有在堆变化时才重新生成前10名。如果k是常数或者最大k是项目总数的一小部分,则缓存思想最有效。

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

这真的归结为集合中有多少项目以及变更的频率与前10名的请求相比。我不需要花费很多项目(几千,我怀疑)一个真正杀死你的线性列表。由于您可以轻松地缓存前10个列表并根据需要重新创建它,因此当集合大小增加时,优先级队列的其他操作的较低成本非常有吸引力。

考虑到这一点,SortedList可能是您想要的混合操作。获得前10名的项目非常快。它易于使用。为什么不制作原型并看看它是否能提供足够好的性能呢?