以下是要求:
您将使用什么数据结构? .NET中是否已存在?还是应该定制?我倾向于后者。
答案 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名的项目非常快。它易于使用。为什么不制作原型并看看它是否能提供足够好的性能呢?