ELFhash - 优秀的字符串哈希算法

分类:算法杂论算法精讲数据结构

(1424)  (2)

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函数计算一般都非常简洁,因此在耗费计算时间复杂性方面判别甚微,这里不作对比。

评估方案设计是这样的:

(1) 以200M的视频文件作为输入源,以4KB的块为大小计算MD5值,并以此作为hash关键字;

(2) 分别应用上面提到的各种字符串hash函数,进行hash散列模拟;

(3) 统计结果,用散列分布性和平均桶长两个指标进行评估分析。

测试程序见附录代码hashtest.c,测试结果如下表所示。从这个结果我们也可以看出,这些字符串hash函数真是不相仲伯,难以决出高低,所以实际应用中可以根据喜好选择。当然,最好实际测试一下,毕竟应用特点不大相同。其他几组测试结果也类似,这里不再给出。

Hash函数 桶数 Hash调用总数 最大桶长 平均桶长 桶使用率%
simple_hash 10240 47198 16 4.63 99.00%
RS_hash 10240 47198 16 4.63 98.91%
JS_hash 10240 47198 15 4.64 98.87%
PJW_hash 10240 47198 16 4.63 99.00%
ELF_hash 10240 47198 16 4.63 99.00%
BKDR_hash 10240 47198 16 4.63 99.00%
SDBM_hash 10240 47198 16 4.63 98.90%
DJB_hash 10240 47198 15 4.64 98.85%
AP_hash 10240 47198 16 4.63 98.96%
CRC_hash 10240 47198 16 4.64 98.77%

所以实际应用中我们可以随便的选取,本文针对ELFhash

3.原理:

首先,我们在开始之前需要明确几点
1.unsigned int有4个字节,32个比特位
2.异或操作中0是单位元,任何数与1异或相当于取反
3.unsigned无符号类型的数据右移操作均是执行逻辑右移(左高位自动补0)
4.ELFhash算法的核心在于“影响“
先附上代码:
[cpp] view plain copy  
  1. unsigned int ELFhash(char *str)
  2. {
  3. unsigned int hash=0;
  4. unsigned int x=0;
  5. while(*str)
  6. {
  7. hash=(hash<<4)+*str;     //1
  8. if((x=hash & 0xf0000000)!=0)         //2
  9. {
  10. hash^=(x>>24);   //影响5-8位,杂糅一次   3
  11. hash&=~x;   //清空高四位    4
  12. }
  13. str++;   //5
  14. }
  15. return (hash & 0x7fffffff);    //6
  16. }

解释:

首先我们的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值

4.Code:

[cpp] view plain copy  
  1. /*#include"iostream"
  2. #include"cstdio"
  3. #include"cstring"
  4. using namespace std;
  5. unsigned int a=0x80;
  6. int main()
  7. {
  8. printf("%d\n",a>>1);   //无符号数实行逻辑右移
  9. return 0;
  10. } */
  11. #include"iostream"
  12. #include"cstdio"
  13. #include"cstring"
  14. using namespace std;
  15. unsigned int ELFhash(char *str)
  16. {
  17. unsigned int hash=0;
  18. unsigned int x=0;
  19. while(*str)
  20. {
  21. hash=(hash<<4)+*str;
  22. if((x=hash & 0xf0000000)!=0)
  23. {
  24. hash^=(x>>24);   //影响5-8位,杂糅一次
  25. hash&=~x;   //清空高四位
  26. }
  27. str++;
  28. }
  29. return (hash & 0x7fffffff);
  30. }
  31. int main()
  32. {
  33. char data[100];
  34. memset(data,0,sizeof(data));
  35. scanf("%s",data);
  36. printf("%d\n",ELFhash(data));
  37. return 0;
  38. }

最后,按照我的思路来看的话,ELFhash最多可以散列的空间的大小是几个亿的数据?如果去掉hash&=~x这一句的话会不会扩大我们hash的范围,尽可能利用空间,我下星期问问数据结构老师好了!

5.应用:

我们在对内存地址的进行的操作的时候,可以将数据的内存地址进行哈希
因为每个数据的内存地址都是唯一的,所以我们只需要一步获取内存地址的十六进制的表示就可以了
语句是
[cpp] view plain copy  
  1. sprintf(data,"%0x",&now_data);

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

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

ELFhash - 优秀的字符串哈希算法相关推荐

  1. 字符串哈希算法简单入门学习

    字符串哈希算法 字符串哈希,最著名的就是BKDRHash,也就是将字符串变成数值,并且最后变成的数值是一个P进制的数(一班取131或者13331),一般来说P最好为素数.然后我们之所以需要前缀和,是因 ...

  2. 一文搞懂负载均衡中的一致性哈希算法

    一致性哈希算法在很多领域有应用,例如分布式缓存领域的 MemCache,Redis,负载均衡领域的 Nginx,各类 RPC 框架.不同领域场景不同,需要顾及的因素也有所差异,本文主要讨论在负载均衡中 ...

  3. 经典的Times 33 哈希算法

    一个好的散列函数通常倾向于"为不相等的对象产生不相等的散列码".理想情况下,散列函数应该把集合中不相等的实例均匀地分布到所有可能的散列值上.要想完全达到这种理想的情形是非常困难的. ...

  4. Hash(哈希(字符串哈希))模板和做题总结(详细易懂)

    文章目录 目录 文章目录 前言: 一 Hash表 1 Hash函数的构造 2 拉链法处理hash冲突模板 3 开放寻址法处理hash冲突 4(例题).雪花雪花 二   字符串Hash O(n)+O(m ...

  5. 数据结构与算法之美-哈希算法

    哈希算法的定义和原理 将任意长度的二进制串映射为固定长度的二进制串. 这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制串就是哈希值. 设计一个优秀的哈希算法需要满足: 从哈希值不能反向推 ...

  6. 群人各说什么是哈希算法?

    这个HASH算法不是大学里数据结构课里那个HASH表的算法.这里的HASH算法是密码学的基础,比较常用的有MD5和SHA,最重要的两条性质,就是不可逆和无冲突. 所谓不可逆,就是当你知道x的HASH值 ...

  7. B00013 字符串哈希函数

    哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值. 哈希函数用途广泛,这个程序给出了绝大多数常用的哈希函数.源程序来自:哈希算法_百度百科. 程序员可以根据自己的 ...

  8. 21 | 哈希算法(上):如何防止数据库中的用户信息被脱库?

    问题:对于用户信息中的密码,你会如何存储用户密码?仅仅 MD5 加密一下存储就够了吗?--哈希算法 什么是哈希算法 哈希算法的定义和原理:将任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规 ...

  9. [一步步学数据结构与算法 20]-哈希算法(上)

    带着问题来学习: 1.如何防止数据库中的用户信息被脱库? 2.你会如何存储用户密码这么重要的数据吗?仅仅 MD5 加密一下存储就够了吗? 3.在实际开发中,我们应该如何用哈希算法解决问题? 一.什么是 ...

最新文章

  1. 简单android音乐播放器课程设计,android音乐播放器课程设计报告.doc
  2. (转载)MyEclipse github
  3. jquery after append appendTo三个函数的区别
  4. zzuli oj 1167逆转数(指针专题)
  5. CentOS 7 用yum安装 MySQL
  6. 对偶图 【BZOJ】1001: [BeiJing2006]狼抓兔子(对偶图+最短路)
  7. Django 使用 mysql 数据库连接
  8. Python3 基础学习笔记 C07【函数】
  9. 信号量sem 的用法
  10. python做一个浏览器_用python做一个简单的浏览器
  11. 西方文学名著鉴赏——英文诗歌翻译赏析
  12. 西瓜书之误差逆传播公式推导、源码解读及各种易混淆概念
  13. 台式电脑开机显示蓝屏 检查计算机上的病毒,电脑出现蓝屏问题的诊断以及处理的方法...
  14. Visual Studio 2022自定义(透明)主题和壁纸完整版
  15. flutter:掌握布局约束Constraint
  16. UVM-入门实验2_uvm代码实现
  17. java计算机毕业设计糖果销售管理系统源码+系统+数据库+lw文档+mybatis+运行部署
  18. HTML5 视频直播那些事儿+吕小鸣博客
  19. 字符串拆分,根据指定分隔符拆分字符串
  20. MAC jmeter+ant 实现接口测试并将接口测试报告以邮件的形式发出-超详细

热门文章

  1. 2022-2028年中国电力行业节能减排投资分析及前景预测报告
  2. Go 学习笔记(67)— Go 并发安全字典 sync.Map
  3. 翻转二叉树 c语言实现 递归 栈 队列
  4. is not a supported wheel on this platform pip安装报错
  5. 机器学习PAL基本概念
  6. Docker App应用
  7. ARMed解决方案对DSP的战争
  8. 人体姿态和形状估计的视频推理:CVPR2020论文解析
  9. 2021年大数据Flink(二十):案例二 基于数量的滚动和滑动窗口
  10. java vector search_java.util.Vector.retainAll()方法实例