Little trick.
1 哈希函数
理想的哈希函数保证每个字符串对应唯一的哈希值。下面这个哈希函数是同学在项目中遇到的。
unsigned int hash(char* s)
{
unsigned int h=0;
for(;*s;s++)
h = *s + h*31;
return h%HASHSIZE; //predefined hash size
}
可以看出,这个hash函数遍历字符串中每个字符,通过将其ASCII码计算得到最终的哈希值h。 这样来确保前面提到的结果唯一性。 我们在gdb中验证一下,有char*
类型的字符串s为nnmm
。s的第i个字符用s[i]
或者*(s+i)
表示。
(gdb) p s
$8 = 0x40071c "nnmm"
(gdb) p s[0]
$11 = 110 'n'
(gdb) p s[1]
$12 = 110 'n'
(gdb) p s[2]
$13 = 109 'm'
(gdb) p *s
$9 = 110 'n'
(gdb) p *s+1
$10 = 111
(gdb) p *(s+1)
$14 = 110 'n'
(gdb) p *(s+2)
$15 = 109 'm'
可以看到,直接打印第i个字符的同时也会输出该字符的ASCII码。 第i个字符在公式中转成ASCII码,然后算出unsigned int型的h。
ASCII码对照表
1.1 哈希函数的对比
[1]中提到编程珠玑中的一个hash函数也是用的类似方法,代码如下:
//用跟元素个数最接近的质数作为散列表的大小
#define NHASH 29989
#define MULT 31
unsigned in hash(char *p)
{
unsigned int h = 0;
for (; *p; p++)
h = MULT *h + *p;
return h % NHASH;
}
除此之外,[1]还对常用字符串哈希函数 BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash进行了量化比较。
1.2 哈希函数分类
[2]中把哈希函数分为如下几类:
- 加法Hash;
- 位运算Hash;
- 乘法Hash;
- 除法Hash;
- 查表Hash;
- 混合Hash;
其中我们上文的函数属于乘法Hash,这种类型的Hash函数利用了乘法的不相关性(乘法的这种性质,最有名的莫过于平方取头尾的随机数生成算法,虽然这种算法效果并不好)。
jdk5.0里面的String类的hashCode()方法也使用乘法Hash。不过,它使用的乘数是31。推荐的乘数还有:131, 1313, 13131, 131313等等。
Reference
- 1 http://www.cnblogs.com/uvsjoh/archive/2012/03/27/2420120.html
- 2 http://blog.csdn.net/linrix/article/details/1938009
2 字符串深度复制
char* str_dump(char* s)
{
int l=strlen(s)+1;
char* ns=(char*)malloc(l*sizeof(char));
strcpy(ns,s);//char *strcpy(char* dest, const char *src)
return ns;// possible be NULL
}