通过密钥和索引进行有效操作和检索的数据结构

时间:2011-10-11 16:30:50

标签: .net data-structures dictionary lookup-tables

我正在寻找具有例如功能的数据结构。 .NET中的OrderedDictionary,也就是说一个关联集合(即将相关联的集合)维护元素顺序(就像一个正常List确实如此)。

必须通过索引和密钥快速查找。它还应该有一个快速“追加”操作(在最后插入一个新项目),以及快速删除任何索引(基于索引或键)的项目。

如果我没有弄错的话,.NET中的OrderedDictionary使用哈希表和数组来存储其项目。因此,基于密钥(或反之亦然)检索索引是 O(n),当然从数组中间删除项目是 O(n)首先,如果按键移除,则从键中添加索引的添加。

我的问题是,是否存在满足我条件的更有效的数据结构,或者这确实是我最好的选择?

4 个答案:

答案 0 :(得分:4)

我认为你可以使用两个红黑树来实现这一点:一个用于存储由比较函数排序的键的键查找树,以及一个索引查找树,其中的键具有任意排序,如列表中所示。每个索引查找节点必须具有“大小”字段 - 如果每个节点中包含“大小”字段,则红黑树可以通过索引进行查找。例如,参见C5 Generic Collection Library中的RedBlackTreeSet实现。

密钥查找树中的每个条目都需要一个指针指向索引查找树中的相应条目。除左节点和右节点指针外,索引查找树还需要父指针字段才能允许从下到上导航以及从上到下。

总之,每个键需要六个指针:两个节点中通常的左右指针,加上从key-lookup-node到index-lookup-node的指针,再加上每个指针中的父指针。索引的查找节点。您还需要在每个节点中指向指向存储的值。

操作:

追加 - 追加操作会将密钥插入到两个树中 - 一次在密钥查找树中,由比较函数确定的位置,再次在索引查找树的最右边位置。插入红黑树是一种对数时间操作。

按键查找 - 这是在键查找树上完成的,使用compare函数找到正确的位置 - O(log(n))

按索引查找 - 这可以在索引查找字段上完成,如上所述 - O(log(n))

从密钥获取索引 - 首先在密钥查找树O(log(n))中查找密钥。按照指针到索引查找树。按照父节点指向根节点,(O(log(n))获得平衡树)。在上升途中使用“大小”字段来确定密钥的索引。 - 总体而言O(log(n))。

按索引删除 - 在索引查找树中查找该项。从索引查找树中删除。在密钥查找树中查找定位的密钥。从密钥查找树中删除。所有操作都是O(log(n)),因此delete总体为O(log(n))。

按键删除 - 使用“从键获取索引”来获取键的索引。从索引查找树中按索引删除。从键查找树中按键删除。 O(log(n))整体。

此结构还支持在任意位置插入O(log(n)),而不仅仅是在最后。

存储开销显然很大,但仍然是O(n)。时间复杂度满足所有要求。

不幸的是,我不知道这种结构的任何实现。

更新:我发现您可以将树与哈希表组合以获得O(1)按键查找。如上所述,不是使用两个树,而是使用哈希表进行按键查找,使用平衡顺序统计树进行按位查找,如上所述,但哈希表的插槽包含指向平衡树的节点,用于按键进行逐列查找。按键查找现在为O(1),其他所有内容平均保持为O(ln(n))。当然,您现在偶尔会得到O(n)重新哈希惩罚,就像任何哈希表一样。

答案 1 :(得分:3)

OrderedDictionary实际上会满足您的要求。

您对OrderedDictionary的分析不正确。对于基于密钥的查找,实际上是O(1),对于根据this的索引,它实际上是O(1)。

即使是简单的分析也可以通过键或索引进行O(1)查找。数组提供O(1)访问,哈希表提供有效的O(1)访问。

插入/删除是一个更复杂的问题,但是给定的摊销分析仍然是O(1)

该文章声称插入和删除是O(n)。这至少不适用于插入,因为分期分析允许您简单地提高从1到2插入给定元素的“成本”。当插入需要数组调整大小的元素时,后半部分的成本用于支付复制的成本。最后一次插入将花费更长时间,但仍然会进行O(1)摊销,如果你不太可能导致数组调整大小,则只会出现差异。

答案 2 :(得分:2)

也许你会在The C5 Generic Collection Library for C#(来自第233页)

中找到有趣的内容

答案 3 :(得分:1)

你可以像链接一样使用Balanced binary search tree,只是为了定义TreeNode你应该添加你的密钥,但问题是找到元素不是O(1),它是O(log(n))两者都是键和索引(事实上索引不是TreeNode的一部分,相对可以找到),但所有操作都是O(log(n)),并且是基于比较方法的最快的已知方式。