• 你用的哈希函数是什么？
• 你还知道哪些哈希函数？

@[toc]

## 代码

### C代码

unsigned int SDBMHash(char *str)
{
unsigned int hash = 0;

while (*str)
{
// equivalent to: hash = 65599*hash + (*str++);
hash = (*str++) + (hash << 6) + (hash << 16) - hash;
}

return (hash & 0x7FFFFFFF);
}

// RS Hash Function
unsigned int RSHash(char *str)
{
unsigned int b = 378551;
unsigned int a = 63689;
unsigned int hash = 0;

while (*str)
{
hash = hash * a + (*str++);
a *= b;
}

return (hash & 0x7FFFFFFF);
}

// JS Hash Function
unsigned int JSHash(char *str)
{
unsigned int hash = 1315423911;

while (*str)
{
hash ^= ((hash << 5) + (*str++) + (hash >> 2));
}

return (hash & 0x7FFFFFFF);
}

// P. J. Weinberger Hash Function
unsigned int PJWHash(char *str)
{
unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8);
unsigned int ThreeQuarters  = (unsigned int)((BitsInUnignedInt  * 3) / 4);
unsigned int OneEighth      = (unsigned int)(BitsInUnignedInt / 8);
unsigned int HighBits        = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
unsigned int hash            = 0;
unsigned int test            = 0;

while (*str)
{
hash = (hash << OneEighth) + (*str++);
if ((test = hash & HighBits) != 0)
{
hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
}
}

return (hash & 0x7FFFFFFF);
}

// ELF Hash Function
unsigned int ELFHash(char *str)
{
unsigned int hash = 0;
unsigned int x  = 0;

while (*str)
{
hash = (hash << 4) + (*str++);
if ((x = hash & 0xF0000000L) != 0)
{
hash ^= (x >> 24);
hash &= ~x;
}
}

return (hash & 0x7FFFFFFF);
}

// BKDR Hash Function
unsigned int BKDRHash(char *str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
unsigned int hash = 0;

while (*str)
{
hash = hash * seed + (*str++);
}

return (hash & 0x7FFFFFFF);
}

// DJB Hash Function
unsigned int DJBHash(char *str)
{
unsigned int hash = 5381;

while (*str)
{
hash += (hash << 5) + (*str++);
}

return (hash & 0x7FFFFFFF);
}

// AP Hash Function
unsigned int APHash(char *str)
{
unsigned int hash = 0;
int i;

for (i=0; *str; i++)
{
if ((i & 1) == 0)
{
hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
}
else
{
hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
}
}

return (hash & 0x7FFFFFFF);
}

### Java代码：BKDR Hash

package temp;

/**
* JavaPub
*/

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class BKDRHash {
public static int seed = 31; // 31 131 1313 13131 131313 etc..

public static int getHashCode(String str) {
int hash = 0;
for (int i = 0; i != str.length(); ++i) {
char c = str.charAt(i);
hash = seed * hash + c;
}
return hash;
}

public static void main(String[] args) {
int length = 100000;
String str1 = "https://gitee.com/rodert/JavaPub";
System.out.println("str1 :" + str1.hashCode() + " system");
System.out.println("str1 :" + getHashCode(str1) + " custom");

Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i != length; ++i) {
String str = UUID.randomUUID().toString();
map.put(getHashCode(str) + "", str);
}
System.out.println("冲突数为： " + (length - map.size()));
}

}

### ELF Hash详细分析

// ELF Hash Function
unsigned int ELFHash(char *str)
{
unsigned int hash = 0;
unsigned int x = 0;
while (*str)
{
hash = (hash << 4) + (*str++);//hash左移4位，当前字符ASCII存入hash
if ((x = hash & 0xF0000000L) != 0)
{//如果最高的四位不为0，则说明字符多余7个，如果不处理，再加第九个字符时，第一个字符会被移出，因此要有如下处理。
//该处理，如果对于字符串(a-z 或者A-Z)就会仅仅影响5-8位，否则会影响5-31位，因为C语言使用的算数移位
hash ^= (x >> 24);
//清空28-31位。上面其实就是把即将删除的高四位和低5-8位运算一次，和 hash = (hash << 4) + (*str++); 效果相同
hash &= ~x;
}
}
//返回一个符号位为0的数，即丢弃最高位，以免函数外产生影响。(我们可以考虑，如果只有字符，符号位不可能为负)
return (hash & 0×7FFFFFFF);

文字一点都不多，认真阅读理解透彻，大有裨益

ELFhash 函数在 UNIX 系统 V 版本4 中的“可执行链接格式 ”( Executable and Linking Format，即ELF ) 中会用到，ELF 文件格式用于存储可执行文件与目标文件。ELFhash 函数是对字符串的散列。它对于长字符串和短字符串都很有效，字符串中每个字符都有同样的作用，它巧妙地对字符的 ASCII 编码值进行计算，ELFhash函数对于能够比较均匀地把字符串分布在散列表中。

int 为32位 ，即  00000000  00000000   00000000   00000000
hash = (hash << 4) + (*str++);//hash 左移4位，当前字符 ASCII 存入 hash

if ((x = hash & 0xF0000000L) != 0)
0xF0000000L 表示28-31位这4位是1，后28为均为0的长整型（L），该操作的结果为 x 保存 hash 的高4位
& 按位与 如果两个相应的二进制位都为 1，则该位的结果值为1，否则为0
hash ^= (x >> 24);

^ 按位异或 若参加运算的两个二进制位值相同则为 0，否则为 1
hash &= ~x;

//返回一个符号位为0的数，即丢弃最高位，以免函数外产生影响。(我们可以考虑，如果只有字符，符号位不可能为负)
return (hash & 0×7FFFFFFF);