如何散列和检查具有循环引用的对象的相等性

Posted

技术标签:

【中文标题】如何散列和检查具有循环引用的对象的相等性【英文标题】:How to hash and check for equality of objects with circular references 【发布时间】:2011-05-31 05:57:48 【问题描述】:

我有一个由 Node 对象表示的 循环 图状结构。 Node 是一个标量值(叶)或 n>=1 个节点(内部节点)的列表。

由于可能存在循环引用,我不能简单地使用递归 HashCode() 函数,它将所有子节点的 HashCode() 组合起来:它会以无限递归结束。

虽然 HashCode() 部分似乎至少可以通过标记和忽略已经访问过的节点来实现,但我很难为 Equals() 考虑一个有效且有效的算法。

令我惊讶的是,我没有找到任何有用的信息,但我相信很多聪明人已经想到了解决这些问题的好方法......对吧?

示例(python):

A = [ 1, 2, None ]; A[2] = A  
B = [ 1, 2, None ]; B[2] = B

A 等于 B,因为它表示完全相同的图。

顺便说一句。此问题不针对任何特定语言,但在 Java 中为描述的 Node 对象实现 hashCode() 和 equals() 将是一个很好的实际示例。

【问题讨论】:

【参考方案1】:

如果您将此视为图,叶节点是一个只有一个连接的节点,而一个复杂节点是一个至少有 2 个连接的节点。因此,您可以这样理解,实现一个简单的 BFS 算法,然后应用哈希函数到它传递的每个节点,然后丢弃结果。这样您就可以确保自己不会掉入圈中或多次通过任何节点。

实施可能非常简单。阅读它here。

【讨论】:

感谢您的回复,但这对我没有帮助: 在知道所有子节点的哈希值之前,我无法计算节点的哈希值。使用 BFS 或 DFS,我可以避免无限递归,但如果有循环,我得到的哈希可能不是一个好的哈希:例如,当我忽略我第二次看到的节点时,节点的哈希将是相同的作为没有循环的节点。我一直在寻找一些有意义的散列算法,并且不会引入不必要的冲突(如果这种情况存在的话)。【参考方案2】:

您需要遍历图表。

这里有一个问题:这些图是否相等?

A = [1,2,None]; A[2] = A
B = [1,2,[1,2,None]]; B[2][2] = B

如果是这样,您需要一组 (Node, Node) 元组。使用该集合捕获循环,并在捕获循环时返回“true”。

如果没有,您可以提高一点效率,并使用从节点到节点的映射。然后,在遍历图表时,建立一组对应关系。 (在上面的例子中,A 对应于 B,A[2] 对应于 B[2],等等。)然后,当您访问一个节点对时,您要确保准确的对在映射中;如果不是,则图表不匹配。

【讨论】:

【参考方案3】:

我也想知道一个好的答案。到目前为止,我使用的是基于访问集的解决方案。

在计算哈希时,我会遍历图结构并保留一组访问过的节点。我没有两次进入同一个节点。当我点击一个已经访问过的节点时,哈希返回一个没有递归的数字。

这甚至适用于相等比较。我比较节点数据并递归调用子节点。当我点击一个已经访问过的节点时,比较返回 true 而不递归。

【讨论】:

以上是关于如何散列和检查具有循环引用的对象的相等性的主要内容,如果未能解决你的问题,请参考以下文章

具有循环引用的对象上的 in_array

散列和散列码

如何在不违反主键约束的情况下插入具有循环引用的实体框架

为啥iOS的Masonry中的self不会循环引用

【OC梳理】循环引用及解决

python_如何在循环引用中管理内存?