【发布时间】:2011-02-07 21:36:12
【问题描述】:
所以在维基百科的hash maps article 中有这张漂亮的图片:
到目前为止一切都清楚了,除了中间的哈希函数。
- 函数如何从任何字符串生成正确的索引?索引实际上也是整数吗?如果是,函数如何输出
1为John Smith,2为Lisa Smith等?
【问题讨论】:
所以在维基百科的hash maps article 中有这张漂亮的图片:
到目前为止一切都清楚了,除了中间的哈希函数。
1 为John Smith,2 为Lisa Smith 等?【问题讨论】:
这是哈希图/字典等的关键问题之一。你必须选择一个好的散列函数。一个非常糟糕但快速的哈希函数可能是键的长度。您会立即看到,您会遇到很多冲突(不同的键,但相同的哈希)。另一个不好的哈希函数可能是密钥第一个字符的 ASCII 值。也有很多碰撞。
所以你需要一个比这两个更好的功能。例如,您可以添加(异或)关键字符的所有 ASCII 值并混合长度。在实践中,您通常依赖于要散列的对象的值(字段)(相同的值给出相同的散列 => 值类型)。例如,对于引用类型,您可以混合在内存位置中。
在您的示例中,这只是简化了很多。没有真正的哈希函数会将这些键映射到序列号。
也许你想读一读我的previous answers to hashmaps
【讨论】:
一个简单的哈希函数可能如下:
$hash = $string[0] % HASH_TABLE_SIZE;
此函数将返回一个介于 0 和 HASH_TABLE_SIZE - 1 之间的数字,具体取决于字符串的第一个字母。这个数字可以用来在哈希表中找到正确的位置。
一个真正的哈希函数会考虑一个字符串中的所有字母,它会被设计成在桶之间有一个均匀的分布。
【讨论】:
散列函数最经常(但不一定总是)输出所需范围内的整数(通常是散列函数的参数)。这个整数可以用作索引。请注意,当给定不同的数据进行散列时,散列函数不能保证总是产生唯一的结果。这称为哈希冲突,哈希算法必须始终以某种方式处理它。
至于您的具体问题,字符串如何变成数字。任何字符串都由字符(J、o、h、n ...)组成,并且字符可以解释为数字(在计算机中)。 ASCII 和 UTF 标准将某些值绑定到某些字符,因此结果是确定性的,并且在所有计算机上始终相同。因此哈希函数对这些字符进行操作,将它们处理为数字并得出另一个数字(输出)。例如,您可以简单地将所有值相加并使用模运算来限制结果值的范围。
这将是一个非常可怕的散列函数,因为例如“ab”和“ba”会得到相同的结果。哈希函数的设计很困难,所以除非情况需要其他解决方案,否则应该使用一些现成的算法。
【讨论】:
在 MSDN 上有一篇关于哈希函数(和碰撞检测/解决)的非常好的文章:
Part 2: The Queue, Stack, and Hashtable
您可以跳到标题使用散列函数压缩序数索引
有些部分是 .NET 特定的(当他们谈论 .NET 默认使用哪种哈希算法时),但大多数情况下它与语言无关。
【讨论】:
散列函数所需要的只是它在给定相同键的情况下返回相同的整数。从技术上讲,始终返回 '1' 的哈希函数是不正确的。
【讨论】: