一、hash算法简介

Hash算法网上也有很多资料,本次大致讲解汇总一下。
Hash即散列,散列方法是根据入参取其中的关键字key作为变量,通过函数公式h(K)(称为散列函数)得到一个函数值,这个函数值一般就是数组的下标,相应的输入信息就存入改下标的内存处,检索时,用同样的方法计算地址,然后到相应的单元里去取要找的结点。一般使用hash算法就是为了快速查找,用内存来换时间,一般在性能提升的时候,大多数当for循环太多的时候,查找特别耗性能,就建议使用hash算法替代for循环,在工作中能胜任大部分的性能提升。
引用别人的博客一段一段话:(https://www.jianshu.com/p/f9239c9377c5)
按散列存储方式构造的存储结构称为散列表(hash table)。散列表中的一个位置称为槽(slot)。散列技术的核心是散列函数(hash function)。 对任意给定的动态查找表DL,如果选定了某个“理想的”散列函数h及相应的散列表HT,则对DL中的每个数据元素X。函数值h(X.key)就是X在散列表HT中的存储位置。插入(或建表)时数据元素X将被安置在该位置上,并且检索X时也到该位置上去查找。由散列函数决定的存储位置称为散列地址。 因此,散列的核心就是:由散列函数决定关键码值(X.key)与散列地址h(X.key)之间的对应关系,通过这种关系来实现组织存储并进行检索。

二、关键点

我们假设我们申请的是一个HT[N]的内存空间保存我们存储的信息,我们需要保存的信息格式肯定小于等于N个,正常理想的情况,我们存储的N个节点信息分散各个下标的内存空间里,没有冲突,事实hash函数计算的结果不可能这么分散,肯定不同的输入经过hash函数得到相同的值,这样内存就冲突了,所以我们hash算法抓住几个关键点:输入入参,入参关键字,hash函数,hash值,冲突。,其中最核心设计hash函数和解决冲突。

三、散列函数

散列函数有很多方法,具体场景具体使用相应的算法,网上也可以查找很多方法借鉴。散列函数设计的要点尽可能避免冲突,同时冲突桶的深度不能太高,太高的话仍然耗性能。
一般的说,Hash函数可以简单的划分为如下几类:

  1. 加法Hash;
  2. 位运算Hash;
  3. 乘法Hash;
  4. 除法Hash;
  5. 查表Hash;
  6. 混合Hash;

一般工作用的较多的是取模和位运算Hash方法,下面介绍的使用取模方法。
取模:除余法就是用关键码x除以M(往往取散列表长度),并取余数作为散列地址。除余法几乎是最简单的散列方法,散列函数为: h(x) = x mod M
位运算Hash:先移位,然后再进行各种位运算是这种类型Hash函数的主要特点

四、冲突解决方法

hash算法另一个难点就是解决冲突,当冲突的实时如何插入管理节点资源,删除,查证。
冲突解决技术可以分为两类:开散列方法( open hashing,也称为拉链法,separate chaining )和闭散列方法( closed hashing,也称为开地址方法,open addressing )
最经典的莫过于拉链法。

拉链法 的实现比较简单,将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可
实现步骤
1)得到一个 key
2)计算 key 的 hashValue
3)根据 hashValue 值定位到 data[hashValue] 。( data[hashValue] 是一条链表)
4)若 data[hashValue] 为空则直接插入
5)不然则添加到链表末尾

另外一个闭散列方法(开放地址法)暂时不介绍了,平时工作用的少,可以百度借鉴其他文章。

五、实战演练

假设有10000个资源需要存储,申请10000个大小的数组,但是怎么根据请求信息来快速定位数组的下标,获取相应的资源信息。我们设计相应的hash算法,有增加,删除,查找接口,满足正常的使用需求。

#include <stdio.h>
#include <string.h>
#include<stdlib.h>#define HASH_NODE_NUM  10000#define HASH_MOD_PRIMER     ((HASH_NODE_NUM/8)*4+13)
/*链表表头节点*/
typedef struct
{int hashcount;int headindex;int tailindex;
}HASH_BUCKET_HEAD;typedef struct
{int id;int flag;int preindex;int nextindex;
}HASH_ITEM_POOL;int Hash_Find_Node(int id, int flag, HASH_BUCKET_HEAD *pBuckethead,HASH_ITEM_POOL *pItempool)
{HASH_ITEM_POOL* ptItem = NULL;HASH_BUCKET_HEAD *pHashHead = NULL;int key = 0;int hashcount = 0;int ntxindex = 0;if ( NULL == pBuckethead || NULL == pItempool ){return -1;}key = id % HASH_MOD_PRIMER;pHashHead = &pBuckethead[key];hashcount = pHashHead->hashcount;if(0 == hashcount){return -1;}ntxindex = pHashHead->tailindex;while(hashcount--){if(ntxindex >= HASH_NODE_NUM){return -1;}ptItem = &pItempool[ntxindex];if(id == ptItem->id && flag == ptItem->flag){return ntxindex;}if(ntxindex == pHashHead->headindex){break;}ntxindex = pItempool->preindex;}return -1;
}int AddIndexToHash(int index, int id, int flag,HASH_BUCKET_HEAD *pBuckethead, HASH_ITEM_POOL *pItempool)
{HASH_BUCKET_HEAD *pHashHead = NULL;int key = 0;int val = -1;if ( NULL == pBuckethead || NULL == pItempool ){return -1;}key = id % HASH_MOD_PRIMER;pHashHead = &pBuckethead[key];if(NULL == pHashHead){return -1;}if(0 == pHashHead->hashcount){pItempool[index].preindex = 0xFFFFFFFF;pItempool[index].nextindex = 0xFFFFFFFF;pHashHead->headindex = index;pHashHead->tailindex = index;pHashHead->hashcount++;return 0;}val = Hash_Find_Node(id, flag, pBuckethead,pItempool);if(-1 != val){return -1;}pItempool[pHashHead->headindex].preindex = index;pItempool[index].nextindex = pHashHead->headindex;pItempool[index].preindex = 0xFFFFFFFF;pHashHead->headindex = index;pHashHead->hashcount++;return 0;
}int DelIndexFromHash(int index, int id, int flag,HASH_BUCKET_HEAD *pBuckethead, HASH_ITEM_POOL *pItempool)
{ HASH_BUCKET_HEAD *pHashHead = NULL;HASH_ITEM_POOL *pItem = NULL;int key = 0;int val = -1;if ( NULL == pBuckethead || NULL == pItempool ){return -1;}pItem = &pItempool[index];key = id % HASH_MOD_PRIMER;pHashHead = &pBuckethead[key];if(NULL == pHashHead){return -1;}if(0 == pHashHead->hashcount){return -1;}if(0xFFFFFFFF != pItem->preindex){pItempool[pItem->preindex].nextindex = pItem->nextindex;}else{pHashHead->headindex = pItem->nextindex;}if(0xFFFFFFFF != pItem->nextindex){pItempool[pItem->nextindex].preindex = pItem->preindex;}else{pHashHead->tailindex = pItem->preindex;}pItem->preindex = 0xFFFFFFFF;pItem->nextindex = 0xFFFFFFFF;pHashHead->hashcount--;return 0;
}void Show_Hash_Info(HASH_BUCKET_HEAD *pBuckethead, HASH_ITEM_POOL *pItempool)
{int i = 0;for(i= 0;i< HASH_MOD_PRIMER;i++){if(pBuckethead[i].hashcount == 0){printf("index:%d hashcount is 0\n",i);continue;}else{printf("index:%d hashcount is %d    ",i,pBuckethead[i].hashcount);int cur = pBuckethead[i].headindex;while(cur != pBuckethead[i].tailindex){printf("%d--->",cur);cur = pItempool[cur].nextindex;}printf("%d",cur);}printf("\n");}
}int main()
{HASH_BUCKET_HEAD *pBuckethead = (HASH_BUCKET_HEAD*)malloc(sizeof(HASH_BUCKET_HEAD) * HASH_MOD_PRIMER);HASH_ITEM_POOL *pItempool = (HASH_ITEM_POOL*)malloc(sizeof(HASH_ITEM_POOL)*HASH_NODE_NUM);int i = 0;int index = -1;/*初始化hash链表桶*/for(; i< HASH_MOD_PRIMER; i++){pBuckethead[i].hashcount = 0;pBuckethead[i].headindex = 0xFFFFFFFF;pBuckethead[i].tailindex = 0xFFFFFFFF;}/*初始化前驱和后继*/for(; i< HASH_NODE_NUM; i++){pItempool[i].preindex = 0xFFFFFFFF;pItempool[i].nextindex = 0xFFFFFFFF;}/*1.插入节点*/for(i = 0; i < HASH_NODE_NUM;i++){pItempool[i].id = i*2;pItempool[i].flag = 10000+i*3;if(-1 == AddIndexToHash(i, pItempool[i].id, pItempool[i].flag,pBuckethead, pItempool)){printf("Add Hash Fail:%d\n",i);}}/*2.打印hash*/Show_Hash_Info(pBuckethead,pItempool);printf("-------------------------------\n");/*3.查找节点*/index = Hash_Find_Node(100, 10150, pBuckethead,pItempool);if(-1 != index){printf("index:%d\n",index);printf("id:%d\n",pItempool[index].id);printf("flag:%d\n",pItempool[index].flag);}else{printf("Find Fail!\n");}printf("-------------------------------\n");/*4.删除节点*/for(i = 0; i < HASH_NODE_NUM;i++){if(-1 == DelIndexFromHash(i,i*2, 10000+i*3,pBuckethead,pItempool)){printf("Del Fail:%d!\n",i);}}Show_Hash_Info(pBuckethead,pItempool);printf("-------------------------------\n");/*5.在查找节点*/index = Hash_Find_Node(100, 10150, pBuckethead,pItempool);if(-1 != index){printf("index:%d\n",index);printf("id:%d\n",pItempool[index].id);printf("flag:%d\n",pItempool[index].flag);}else{printf("Find Fail!\n");}/*6.释放内存*/free(pBuckethead);pBuckethead = NULL;free(pItempool);pItempool = NULL;return 0;
}

哈希(HASH)算法总结相关推荐

  1. 聊聊传说中的散列哈希Hash算法,以及Java中的HashTable,HashMap,HashSet,ConcurrentHashMap......

    建议本文结合java源码来阅读,看了之后就什么都懂了,还有参考文献. 散列(Hash) 是一种按关键字编址的存储和检索方法 散列表(HashTable)根据元素的关键字确定元素的位置 散列函数(Has ...

  2. 常见的哈希Hash算法 MD5 对称非对称加密 海明码

    2019独角兽企业重金招聘Python工程师标准>>> 参考 Link 另外,这篇文章也提到了利用Hash碰撞而产生DOS攻击的案例: http://www.cnblogs.com/ ...

  3. 【IoT】加密与安全:哈希 Hash 算法用途与原理解析

    1.Hash 算法分类 MD5 和 SHA-1 是目前应用最广泛的 Hash 算法且是以 MD4 算法为基础设计的. 1) MD4 MD4(RFC 1320) 是 MIT 的 Ronald L. Ri ...

  4. php+mysql分库分表的哈希(hash)算法

    转自:http://itlab.idcquan.com/linux/PHP/905174.html php+mysql分库分表的哈希(hash)算法: 我们在实际开发的时候,难免会遇到大访问量的问题, ...

  5. 【编程实践】一致性哈希(hash)算法实现

    目录 1 为什么使用一致性哈希 1.1 我该访问谁? 1.2 节点数量变化了怎么办? 2 算法原理 2.1 步骤

  6. 一致性hash算法_(图文案例)一致性哈希算法详解 一点课堂(多岸教育)

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  7. 布谷鸟哈希函数的参数_系统学习hash算法(哈希算法)

    系统学习hash算法(哈希算法) 转载请说明出处. 前言: 关于本文<系统学习hash算法>的由来.在看到了<十一.从头到尾彻底解析Hash 表算法>这篇文章之后,原文中没有暴 ...

  8. java常见的hash算法_常见的哈希算法和用途

    写在前面 哈希算法经常会被用到,比如我们Go里面的map,Java的HashMap,目前最流行的缓存Redis都大量用到了哈希算法.它们支持把很多类型的数据进行哈希计算,我们实际使用的时候并不用考虑哈 ...

  9. Hash哈希查找算法

    今天面试中遇到一个查找问题,典型的属于哈希查找算法可以解决,我居然懵逼了很尴尬 ̄□ ̄||,之前在数据结构中学过Hash表,后来有没有复习,现在在这里再总结归纳一下吧. 没有复习之前提到Hash我一直以 ...

  10. 算法学习笔记 - 哈希(Hash)

    Hash表 Hash 表又称为散列表,一般由 Hash 函数(散列函数)与链表结构共同实现.与离散化思想类似,当我们要对若干复杂信息进行统计时,可以用 Hash 函数把这些复杂信息映射到一个容易维护的 ...

最新文章

  1. 汇总|实时性语义分割算法
  2. 【Prometheus + Grafana】 使用 topk 在 grafana 绘制 前 n 个时间序列
  3. 正则表达式之子表达式 ‘()’ 中表达式 '[]' 大表达式 '{}'
  4. 阶段3 3.SpringMVC·_01.SpringMVC概述及入门案例_06.入门案例的流程总结
  5. py将dicm格式图片转为jpg格式
  6. 解决一例Fedora 31安装NVIDIA官方驱动程序无法使用DKMS注册的问题
  7. python正则匹配内网IP
  8. Anbox源码分析(三)——Anbox渲染原理(源码分析)
  9. Unicode双向算法详解(bidi算法)(三)
  10. 教你使用Python爬虫获取电子书资源实战!喜欢学习的小伙伴过来看啦!
  11. 2020年史上最全移动端Web整理从开发基础到实战(四)
  12. 如何查询计算机com口使用
  13. 学习《GUI Qt4 编程》笔记-02-代码实现控件布局-设计师控件布局
  14. 【OC】JSONModel基本使用
  15. css 所有选择器 实例与总结
  16. linux创建蓝光映像光盘,11.13 mkisofs指令:创建光盘映像文件
  17. java自学能学会吗_自学java能学会吗?有没有捷径能尽快学会?
  18. 上海迪士尼将于今年九月开启达菲主题月
  19. Android:代码混淆反混淆
  20. html翻译系统,如何实现网页自动翻译成终端系统的文字?

热门文章

  1. 剖析系统虚拟化(2)- X86虚拟化技术
  2. linux查看cpu主频
  3. atmega16应用之DS18B20温度传感器
  4. 无线传感网络 --ZigBee2-2定时器
  5. 英语单词: trunk
  6. 悟空CRM (基于jfinal+vue+ElementUI的前后端分离CRM系统)
  7. 怎样让自我评价变成简历最出彩的地方?
  8. C++ opencv视频文件摄像头使用
  9. 《Parcel打包工具的使用》
  10. Windows提示缺少msxml3.dll文件如何解决?