在我正在开发的程序中,我开发了一个大的“线程树”(每个节点最多k个子节点),其中每个线程对从其父节点继承的哈希表进行一些修改。有没有办法实现一个有点“持久”的哈希表(在http://en.wikipedia.org/wiki/Persistent_data_structure意义上)?
即,有没有办法实现一个键值配对,至少O(log n)查找,插入和删除是完全持久的,但是作为“节省空间”(最坏情况)普通的哈希表?
答案 0 :(得分:5)
“作为普通哈希表的空间效率”是一个相当模糊的规范,因为“普通”可能意味着根据您的要求链接或探测。我认为还没有人设计易于理解的持久性哈希表。
获取具有所需复杂性的持久键值映射的最简单方法是使用持久二进制搜索树。查找是临时(非持久)BST的熟悉算法。然而,插入更改,变成类似(伪Java):
// overwrites the value for k if it's already in the tree
Node insert(Node node, Key k, Value v)
{
if (k < node.key)
return new Node(node.key, node.val, insert(node.left, k, v), node.right);
else if (k > node.key)
return new Node(node.key, node.val, node.left, insert(node.right, k, v));
else
return new Node(k, v, node.left, node.right);
}
请注意,insert例程返回一个新树,这可能看起来效率低下,但它只会更改它遍历的那些节点。这平均为O(lg n ),因此它平均分配O(lg n )。这个空间效率非常高。
要获得最坏情况的O(lg n )行为,请使用红黑树。另见有关函数式编程中数据结构的文献,例如:冈崎的作品。
答案 1 :(得分:2)
确实有。很多方式。有没有办法实现一个键值配对,至少O(log n)查找,插入和删除是完全持久的,但是像普通哈希那样“节省空间”(最坏情况) -table?
E.g。在Haskell中,简单Data.Map
,大小平衡二叉树(或有界平衡树)如下所述:
提供以下API,满足您的条件:
insert :: Ord k => k -> a -> Map k a -> Map k a -- O(log n)
lookup :: Ord k => k -> Map k a -> Maybe a -- O(log n)
delete :: Ord k => k -> Map k a -> Map k a -- O(log n)
同时完全持久。空间使用是 O(n)。
对于更好的恒定因子,请尝试例如一个Data.HashMap
数据结构,具有相同的整体复杂性。
替代结构包括:
答案 2 :(得分:1)
Clojure实现了一整套持久性数据结构,例如哈希映射。它是开源的,所以也许你应该看一下?
http://clojure.org/data_structures
http://code.google.com/p/clojure/source/browse/trunk/src/jvm/clojure/lang/PersistentHashMap.java
答案 3 :(得分:1)
也就是说,有没有办法实现一个键值配对,至少O(log n)查找,插入和删除是完全持久的,但是节省空间&#34; (最坏情况)作为普通的哈希表?
是。 Driscoll等人的"Making Data Structures Persistent"第5节展示了一种技术,用于制作具有O(lg n)时间和O(1)空间复杂度的完全持久的红黑树,用于插入,删除和查找。
他们的数据结构不是一成不变的。有关持久性的更多信息,请参阅Kaplan's survey on the topic。
答案 4 :(得分:0)
您是否尝试过或审核过jdbm2的来源? http://code.google.com/p/jdbm2/