持久哈希表实现

Posted

技术标签:

【中文标题】持久哈希表实现【英文标题】:Persistent Hash Table Implementation 【发布时间】:2011-06-19 03:08:42 【问题描述】:

在我正在开发的一个程序中,我开发了一个大型“线程树”(每个节点最多 k 个子节点),其中每个线程对从其父节点继承的哈希表进行一些修改。有没有办法实现一个有点“持久”的哈希表(在http://en.wikipedia.org/wiki/Persistent_data_structure 的意义上)?

也就是说,有没有一种方法可以实现一个键值对,它至少具有 O(log n) 的查找、插入和删除功能,并且是完全持久的,但“节省空间”(最坏情况)普通的哈希表?

【问题讨论】:

在那篇***文章中至少有 5 种不同的持久性,你在寻找什么样的持久性? 完全持久化,刚刚更新了原帖 如果我很好地理解了您的问题,如果您希望每个孩子从他的父母那里继承哈希表,您可以在每次创建/添加孩子时制作哈希表的深层副本。 @Muggen:每次分娩都需要 O(n) 操作。持久数据结构将其降低到 O(1),代价是查找、插入和删除操作的 O(lg n)。 您使用的是 Java 还是 C++? 【参考方案1】:

“与普通哈希表一样节省空间”是一个相当模糊的规范,因为“普通”可能意味着链接或探测,具体取决于您询问的对象。我认为还没有人设计出易于理解的持久哈希表。

获得具有所需复杂性的持久键值映射的最简单方法是使用持久二叉搜索树。查找是来自短暂(非持久)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);

请注意,插入例程返回一棵新树,这可能看起来效率低下,但它只会更改它遍历的那些节点。这平均为 O(lg n),因此它平均执行 O(lg n) 次分配。这样可以节省空间。

要获得最坏情况的 O(lg n) 行为,请使用红黑树。另请参阅有关函数式编程中数据结构的文献,例如冈崎的作品。

【讨论】:

+1 用于提及冈崎的作品;如果你能找到他关于纯函数式数据结构的书的副本,你就可以获得解决这个问题的各种有趣的解决方案。【参考方案2】:

有没有办法实现一个键值对,至少 O(log n) 的查找、插入和删除是完全持久的,但与普通哈希一样“节省空间”(最坏情况) -桌子?

确实有。方法很多。

例如在 Haskell 中,简单的 Data.Map,一个 大小平衡 二叉树(或有界平衡树),如下所述:

Stephen Adams,“Efficient sets: a balance act”,Journal of Functional Programming 3(4):553-562,1993 年 10 月,http://www.swiss.ai.mit.edu/~adams/BB/。 J. Nievergelt 和 E.M. Reingold,“有界平衡的二叉搜索树”,SIAM 计算杂志 2(1),1973 年 3 月。

提供以下 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 数据结构,具有相同的整体复杂性。

替代结构包括:

持久性尝试,与哈希表相比提高了空间使用率,因为密钥存储很密集。

【讨论】:

由于使用路径复制进行插入和删除工作,我认为每次插入都会花费 Omega(lg n) 空间,因此维护 k 个版本可能会花费 Omega(n + k lg n) 空间。【参考方案3】:

Clojure 实现了一整套持久性数据结构,例如哈希映射。它是开源的,所以也许你应该看看?

http://clojure.org/data_structures

http://code.google.com/p/clojure/source/browse/trunk/src/jvm/clojure/lang/PersistentHashMap.java

【讨论】:

【参考方案4】:

也就是说,有没有一种方法可以实现一个键值对,它至少具有 O(log n) 的查找、插入和删除功能,并且是完全持久的,但“节省空间”(最坏情况)普通的哈希表?

是的。 Driscoll 等人的"Making Data Structures Persistent" 的第 5 节展示了一种技术,用于制作具有 O(lg n) 时间和 O(1) 空间复杂度的完全持久性红黑树,用于插入、删除和查找。

他们的数据结构不是持续一致的。有关持久性的更多信息,请参阅Kaplan's survey on the topic。

【讨论】:

这篇论文对于理论上的考虑很好,但是那里有一些实际的 C 代码可以实现持久的红黑树吗?似乎我发现的所有库(例如 GNU libavl)都不是持久性的,如果不增加持久性,理解红黑树就已经够难了... 使用 Google 与关键字:持久性红黑 driscoll

以上是关于持久哈希表实现的主要内容,如果未能解决你的问题,请参考以下文章

哈希表(JavaScript实现)

使用python实现哈希表字典集合

稀疏哈希表背后的主要实现思想是啥?

哈希算法和哈希表的区别?

❤️数据结构入门❤️(1 - 8)- 哈希表

Python实现哈希表