ELFhash - 字符串哈希算法

1.字符串哈希:

在很多的情况下,我们有可能会获得大量的字符串,每个字符串有可能重复也有可能不重复 

C不像Python有字典类型的数据结构,我们没有办法吧字符串当做是键值来保存,所以说我们需要一种hash函数将每个字符串都尽可能减少冲突的情况下,去应设一个唯一的整形数据,方便我们的保存,这里我们就引入了字符串hash算法

现在,有非常多的字符串hash算法都很优秀,本文主要面对ELFhash算法来表述,相对来说比较的清晰             

2.ELFhash算法

首先我需要声明,字符串hash算法ELFhash的算法的形成的三列的均匀性我不会证明

根据其他的大牛的描述,ELFhash算法对于长字符串和短字符串都有优良的效率,以下的数据援引刘爱贵大神的实验数据:

Hash应用中,字符串是最为常见的关键字,应用非常普通,现在的程序设计语言中基本上都提供了字符串hash表的支持。字符串hash函数非常多,常见的主要有Simple_hash, RS_hash, JS_hash, PJW_hash, ELF_hash, BKDR_hash, SDBM_hash, DJB_hash, AP_hash, CRC_hash等。它们的C语言实现见后面附录代码: hash.h, hash.c。那么这么些字符串hash函数,谁好熟非呢?评估hash函数优劣的基准主要有以下两个指标:

(1) 散列分布性

即桶的使用率backet_usage = (已使用桶数) / (总的桶数),这个比例越高,说明分布性良好,是好的hash设计。

(2) 平均桶长

即avg_backet_len,所有已使用桶的平均长度。理想状态下这个值应该=1,越小说明冲突发生地越少,是好的hash设计。

hash函数计算一般都非常简洁,因此在耗费计算时间复杂性方面判别甚微,这里不作对比。

3.原理:

首先,我们在开始之前需要明确几点

1.unsigned int有4个字节,32个比特位

2.异或操作中0是单位元,任何数与1异或相当于取反

3.unsigned无符号类型的数据右移操作均是执行逻辑右移(左高位自动补0)

4.ELFhash算法的核心在于“影响“

unsigned int ELFhash(char *str)
{
    unsigned int hash,x=0;
    while(*str){    //*str!='\0'
        hash=(hash<<4)+(*str++);//1
        if((x==hash&0xf0000000)!=0){//2  7个0
            hash^=(x>>24);//影响5-8位,杂糅一次  3
            hash&=~x;//清空高四位  4
        }
        str++;//5
    }
    return (hash&0x7fffffff);//6   7个f
}

解释:

首先我们的hash结果是一个unsigned int类型的数据:

0000 0000 0000 0000

1.hash左移4位,将str插入(一个char有八位)这里我开始也一直是怀疑的态度,那么第一个字节的高四位不就乱了吗

实际上这也是我们的第一次杂糅,我们是故意这么做的,这里我们需要注意标记一下,我们在第一个字节的高四位做了第一次杂糅

2.x这里用0xf0000000获取了hash的第四个字节的高四位,并用高四位作为掩码做第二次杂糅

在这里我们首先声明一下,因为我们的ELFhash强调的是每个字符都要对最后的结构有影响,所以说我们左移到一定程度是会吞掉最高的四位的,所以说我们要将最高的四位先对串产生影响,再让他被吞掉,之后的所有的影响都是叠加的,这就是多次的杂糅保证散列均匀,防止出现冲突的大量出现

3.x掩码右移24位移动到刚才的5-8位哪里在对5-8位进行第二次杂糅

4.我们定时清空高四位,实际上这部操作我们完全没有必要,但是算法要求,因为我们下一次的左移会自动吞掉这四位//这里存疑,不会减少我们的hash的范围?

5.str递增,引入下一个字符进行杂糅

6.返回一个缺失了最高符号位的无符号数(为了之后防止用到了有符号的时候造成的溢出)作为最后的hash值

  ①算术左移同逻辑左移   
  ②算术右移移入的位用符号位填   ,逻辑右移移入的位用0填 

5.应用:

我们在对内存地址的进行的操作的时候,可以将数据的内存地址进行哈希

因为每个数据的内存地址都是唯一的,所以我们只需要一步获取内存地址的十六进制的表示就可以了

语句是

char data[100];
sprintf(data,"%0x",&now_data);

第一个data保存我们的保留字符串的内存空间(字符串数组)

中间的"0x"是保存的进制的形式

最后 now_data 是我们的要取地址的内存空间
利用这种思路,可以很清晰明了的对链表相交的问题构建一种新的解法,采用哈希内存空间就可以了,可以在O(n)中完成查找

猜你喜欢

转载自blog.csdn.net/qq_40507857/article/details/82222539