树形结构的哈希化

51
我刚刚在项目中遇到一个场景,需要将不同的树对象与已知实例进行比较,并考虑到一些对任意树结构进行哈希的算法会非常有用。
以以下树为例:
O / \ / \ O O /|\ | / | \ | O O O O / \ / \ O O
每个 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:确实如此。我修改了问题,以暗示“尽可能无碰撞”。 - Noldorin
2
这些答案都没有很好地解释它,但是一棵树只是一个元组(节点本地数据、子树0、子树1等)。元组是可散列的。完成。更多细节请参见vatine和pnm的答案。 - Jason Orendorff
@Eli Bendersky:就实际目的而言,无冲突是相当简单的。例如,SHA1已经有15年历史了,仅有160位,但即使使用我们最好的超级计算机,也没有人找到过两个具有相同SHA1哈希值的值(尽管我猜很快就会发生这种情况)。 - BlueRaja - Danny Pflughoeft
1
@BlueRaja 是的,但是尝试将SHA1的输出映射到一个可寻址空间,它是一个序列递增的、线性递增的,比如说,1,000个元素长。现在告诉我这不会出现碰撞。 - San Jacinto
会用到Merkle树吗? - Vladimir Panteleev
显示剩余4条评论
11个回答

0
编写自己的哈希函数几乎总是一个错误,因为你基本上需要数学学位才能做到良好。哈希函数极其不直观,并具有高度不可预测的冲突特性。
不要尝试直接组合子节点的哈希码--这将放大底层哈希函数中的任何问题。相反,按顺序连接每个节点的原始字节,并将其作为字节流提供给经过验证的哈希函数。所有加密哈希函数都可以接受字节流。如果树很小,您可能希望只创建一个字节数组并在一个操作中对其进行哈希处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接