转自:https://www.cnblogs.com/xiohao/p/4389672.html
散列表:哈希表,据关键码值key value 直接访问的数线性表数据结构
通过关键码值映射到表中的一个位置来访问记录,加快查找速度:散列函数
函数计算结果是一个存储单位地址,每个存储单位称为“桶”,m个桶、值域[0,m-1]
其中元素间可能存在空隙:负载因子
基于快速存取的角度设计,空间换时间
基于 结果尽可能随机平均分布的固定函数H 为每个元素安排存储位置,避免遍历性质的线程搜索,但因为随机性、导致冲突(两个元素通过散列函数H 相同地址:同义词,哈希表不可避免冲突)
构造散列函数的方法:
散列函数:对一个数据序列的访问过程迅速有效,元素快速定位
1、直接寻址
关键字或关键字的某个线性函数值为散列地址
H(key)=key或H(key) = a?key + b,其中a和b为常数,自身函数
2、数字分析法
分析一组数据,找出数字规律,利用数据构造冲突几率低的散列地址
3、平方取中法
取关键字平方后的中间几位作为散列地址
4、折叠法
将关键字分割成位数相同的几部分,最后一部分位数可不同,然后取这几部分的叠加和(去除进位)
5、随机数法
选择一随机函数,取关键字的随机值作为散列地址:用于关键字长度不同的场合
6、除留余数法
关键字被某个不大于 散列列表长m的数p除后 所得的余数 为散列地址 H(key) = key MOD p, p<=m
不仅可对关键字取模,也可在折叠、平方取中等运算后取模,对p的选择很重要,取素数或m
冲突取决于:
散列函数、处理冲突的方法、负载因子大小(太大不一定好,浪费空间,因子与函数联动)
解决冲突:
1、线程探查法:冲突后、线性向前试探,找最近空位置;会堆积、存取时maybe非同义词的词也位于探查序列,影响效率
2、双散列函数法:在位置d冲突后,再次使用另一散列函数产生一个与散列表桶容量m互质的数c,依次试探(d+n*c)%m,使探查序列跳跃式分布;
两个正整数只有一个公因数1时,它们的关系叫做互质;【源】
查找性能分析:
基本和造表过程相同,一些关键码通散列函数转换地址找到;一些码产生冲突,则按处理冲突方法查找;产生冲突后的查找仍然是给定值与关键码比较的过程;
效率量度:用平均查找长度衡量
查找过程中,关键码比较次数,取决于产生冲突的多少,影响因素:
1、散列函数是否均匀;2、处理冲突的方法;3、散列表的装填因子
装填因子:α= 填入表中的元素个数 / 散列表的长度
α是散列表装满程度的标志因子,由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大填入表的元素较多,产生冲突可能性越大;散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数
hash算法
MD5 和 SHA-1 :目前应用最广泛的Hash算法,都是以 MD4 为基础设计的
1、MD4(RFC 1320) Message Digest ,适用在32位字长的处理器上用高速软件实现--基于 32 位操作数的位操作;
2、MD5(RFC 1321)对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。比MD4复杂,且速度慢一点,但更安全,在抗分析和抗差分方面表现更好;
3、SHA1 对长度小于264的输入,产生长度160bit的散列值,抗穷举(brute-force)性更好。 设计时基于MD4相同原理,且模仿了MD4;
哈希表:根据设定的哈希函数H(key)和所选中的处理冲突的方法,将一组关键字映象到一个有限的、地址连续的地址集(区间)上并以关键字在地址集中的“象”作为相应记录 在表中的存储位置
哈希函数:以f(key)作为关键字 为key的记录在表中的位置,一个映像,将关键字的集合映射到某个地址的集合上,设置灵活、只有地址集合大小不超过容许范围即可;
Hash函数
(也称杂凑函数或杂凑算法)就是把任意长的输入消息串变化成固定长的输出串的一种函数。这个输出串称为该消息的杂凑值。一般用于产生消息摘要,密钥加密等.【源】
加法hash、位运算hash、乘法hash、除法hash、查表hash、混合hash
1)加法hash:把输入元素加起来构成最后的结果
static int additiveHash(String key, int prime)
{
int hash, i;
for (hash = key.length(), i = 0; i < key.length(); i++)
hash += key.charAt(i);//返回索引i处的字符
return (hash % prime);//prime是任意的质数,值域为[0,prime-1]
}
2)位运算:用各种位运算(常见的是移位和异或)来充分的混合输入元素
static int rotatingHash(String key, int prime)
{
int hash, i;
for (hash=key.length(), i=0; i<key.length(); ++i)
//先移位,然后再进行各种位运算
hash = (hash<<4)^(hash>>28)^key.charAt(i);
return (hash % prime);
}
变形:
hash = (hash<<5>>27)^key.charAt(i);
hash += key.charAt(i);
hash += (hash << 10);
hash ^= (hash >> 6);
if((i&1) == 0) {
hash ^= (hash<<7>>3);
} else {
hash ^= ~((hash<<11>>5));
} hash += (hash<<5> hash = key.charAt(i) + (hash<<6>>16) ? hash; hash ^= ((hash<<5>>2));
https://blog.csdn.net/jason5186/article/details/9037623
亦或https://zhidao.baidu.com/question/68565016.html
1:“按位与”运算符(&)用法是如果两个相应的二进制位都为1,则该位的结果值为1否则为0。0&0=0,1&0=0,1&1=1
2:“按位或”运算符(|)用法是如果两个相应的二进制位有一个为1,则该位的结果值为1否则为0。0&0=0,1&0=0,1&1=1
0,1&0=1,1&1=1
3:“异或”运算符(^)用法是如果两个相应的二进制位为同号,则该位的结果值为1否则为0。0&0=1,1&0=0,1&1=1
乘法hash
利用乘法的不相关性(平方取头尾的随机数生成算法)
static int bernstein(String key)
{
int hash = 0;
int i;
for (i=0; i<key.length(); ++i) hash = 33*hash + key.charAt(i);
return hash;
}
jdk5.0里面的String类的hashCode()方法也使用乘法Hash。不过,它使用的乘数是31。推荐的乘数还有:131, 1313, 13131, 131313等等;
// 32位FNV算法
int M_SHIFT = 0;
public int FNVHash(byte[] data)
{
int hash = (int)2166136261L;
for(byte b : data)
hash = (hash * 16777619) ^ b;
if (M_SHIFT == 0)
return hash;
return (hash ^ (hash >> M_SHIFT)) & M_MASK;
}
//改进的FNV算法:
public static int FNVHash1(String data){
final int p = 16777619;
int hash = (int)2166136261L;
for(int i=0;i<data.length();i++)
hash = (hash ^ data.charAt(i)) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
//除了乘以一个固定的数,常见的还有乘以一个不断改变的数,如:
static int RSHash(String str)
{
int b = 378551;
int a = 63689;
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = hash * a + str.charAt(i);
a = a * b;
}
return (hash & 0x7FFFFFFF);
}
除法hash
除法太慢,这种方式几乎找不到真正的应用;
在前面看到的hash的 结果除以一个prime的目的只是为了保证结果的范围;
查表Hash
查表Hash中有名的例子有:Universal Hashing和Zobrist Hashing。他们的表格都是随机生成的;
混合Hash
混合Hash算法利用了以上各种方式。各种常见的Hash算法,比如MD5、Tiger都属于这个范围。它们一般很少在面向查找的Hash函数里面使用
作用
1)文件校验
MD5 Hash的“数字指纹”:文件完整性校验和Checksum算法,抗数据篡改
文件hash值:MD5Hash文件的数字文摘通过Hash函数计算得到,结果是固定长度的数字
hash算法不可逆的单向函数,不同文件不太可能得到same结果,so一旦文件被修改,能检查出
2)数字签名
3)鉴权协议
挑战-认证模式:传输信道可被侦听、不可改
限制:
1、主原理:大范围映射到小范围,输入的实际值的个数须<=小范围,否则冲突more
2、不同应用对hash函数有不同要求,如加密hash考虑和单项函数的差距;查找hash考虑映射到小范围的冲突
3、不同应用对hash函数有不同要求,加密hash考虑它和单向函数的差距,查找hash考虑映射到小范围的冲突率
感谢分享:
https://blog.csdn.net/wfg18801733667/article/details/59108337
https://www.cnblogs.com/xiohao/p/4389672.html
感觉好多文章取自同一篇文章,连字符串都一模一样,无可厚非,多谢分享
发现csdn一个人性化的地方,新建博客的时候如果没有专门添加这个分类,在下面建的话会自动帮你建这个类,嗯~可能你们不知道我在说什么,可能也没有人会看到,写出来也不是为了……词穷了,也不知道写出来干啥,再说也不是我写的,复复制制、转载一篇,感才选的‘原创’,赶紧改过来,不废话了,晚上睡不着、诶~