【发布时间】:2010-01-01 14:00:05
【问题描述】:
我刚刚在我的项目中遇到了一个场景,我需要比较不同的树对象与已知实例的相等性,并认为在任意树上运行的某种散列算法将非常有用。
以下面的树为例:
○ / \ / \ 哦哦 /|\ | / | \ | 哦哦哦 / \ / \ 哦哦其中每个O 代表树的一个节点,是一个任意对象,具有关联的哈希函数。所以问题归结为:给定树结构节点的哈希码和已知结构,为整个树计算(相对)无冲突哈希码的体面算法是什么?
关于哈希函数属性的几点说明:
- 哈希函数应取决于树中每个节点的哈希码及其位置。
- 对节点的子节点进行重新排序应该明显改变生成的哈希码。
- 反映树的任何部分应该明显改变生成的哈希码
如果有帮助,我会在我的项目中使用 C# 4.0,尽管我主要是在寻找理论上的解决方案,所以伪代码、描述或其他命令式语言的代码都可以。
更新
嗯,这是我自己提出的解决方案。这里的几个答案对它有很大帮助。
每个节点(子树/叶节点)具有以下哈希函数:
public override int GetHashCode()
{
int hashCode = unchecked((this.Symbol.GetHashCode() * 31 +
this.Value.GetHashCode()));
for (int i = 0; i < this.Children.Count; i++)
hashCode = unchecked(hashCode * 31 + this.Children[i].GetHashCode());
return hashCode;
}
在我看来,这种方法的好处是可以缓存哈希码,并且仅在节点或其后代之一发生更改时才重新计算。 (感谢 vatine 和 Jason Orendorff 指出这一点)。
无论如何,如果人们可以在这里评论我建议的解决方案,我将不胜感激 - 如果它做得很好,那就太好了,否则任何可能的改进都会受到欢迎。
【问题讨论】:
-
@Eli Bendersky:确实如此。我已修改问题以暗示“尽可能无碰撞”。
-
这些答案都不能很好地解释它,但树只是一个元组(节点本地数据、subtree0、subtree1,...)。元组是可散列的。完毕。有关详细信息,请参阅 vatine 和 pnm 的答案。
-
@Jason,知道这一点,我假设(至少在第二次编辑之前)树“太大”而不能仅仅作为元组进行散列。
-
@Eli Bendersky:出于所有实际目的,无碰撞非常简单。例如,SHA1 已有 15 年的历史,只有 160 位,但即使使用我们最好的超级计算机,也没有人找到具有相同 SHA1 哈希值的两个值(尽管我猜这很快就会发生)。
-
@BlueRaja 是的,但是尝试将 SHA1 的输出映射到一个串行且线性增加的可寻址空间,即 1,000 个元素长。现在试着告诉我这将是无碰撞的。
标签: algorithm data-structures tree hash