元素特色转变为数组下标的方法便是散列法。散列法当然不止一种,下面列出三种比较常用的:
除法散列法
公式: index = value % 16
学过汇编的都知道,求模数实在是通过一个除法运算得到的,以是叫“除法散列法”。
平方散列法
求index是非常频繁的操作,而乘法的运算要比除法来得省时(对现在的CPU来说,估计我们觉得不出来),以是我们考虑把除法换成乘法和一个位移操作。
公式: index = (value value) >>28 (右移,除以2^28。记法:左移变大,是乘。右移变小,是除。)
如果数值分配比较均匀的话这种方法能得到不错的结果。大概你还有个问题,value如果很大,value value不会溢出吗?答案是会的,但我们这个乘法不关心溢出,由于我们根本不是为了获取相乘结果,而是为了获取index。
Hash算法的特点正向快速:给定明文和 hash 算法,在有限韶光和有限资源内能打算出 hash 值。
逆向困难:给定(多少) hash 值,在有限韶光内很难(基本不可能)逆推出明文。
输入敏感:原始输入信息修正一点信息,产生的 hash 值看起来该当都有很大不同。
冲突避免:很难找到两段内容不同的明文,使得它们的 hash 值同等(发生冲突)。即对付任意两个不同的数据块,其hash值相同的可能性极小;对付一个给定的数据块,找到和它hash值相同的数据块极为困难。
Hash算法的实现作为散列算法,紧张的功能便是要利用一种算法把原有的体积很大的文件信息用多少个字符来记录,还要担保每一个字节都会对终极结果产生影响。那么大家大概已经想到了,求模这种算法就能知足我们的须要。
事实上,求模算法作为一种不可逆的打算方法,已经成为了全体当代密码学的根基。只假如涉及到打算机安全和加密的领域,都会有模打算的身影。散列算法也并不例外,一种最原始的散列算法便是纯挚地选择一个数进行模运算,比如以下程序。
很显然,上述的程序完成了一个散列算法所应该实现的低级目标:用较少的文本量代表很长的内容(求模之后的数字肯定小于8)。但大概你已经把稳到了,纯挚利用求模算法打算之后的结果带有明显的规律性,这种规律将导致算法将能难担保不可逆性。以是我们将利用其余一种手段,那便是异或。
再来看下面一段程序,我们在散列函数中加入一个异或过程。
很明显的,加入一层异或过程之后,打算之后的结果规律性就不是那么明显了。
当然,大家大概会以为这样的算法依旧很不屈安,如果用户利用连续变革的一系列文本与打算结果比较对,就很有可能找到算法所包含的规律。但是我们还有其他的办法。比如在进行打算之前对原始文本进行修正,或是加入额外的运算过程(如移位),比如以下程序。
这样处理得到的散列算法就很难创造其内部规律,也便是说,我们并不能很轻易地给出一个数,让它经由上述散列函数运算之后的结果即是4——除非我们去穷举测试。
Hash实例加法Hash
所谓的加法Hash便是把输入元素一个一个的加起来构成末了的结果。标准的加法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);
return (hash % prime);
}
这里的prime是任意的质数,看得出,结果的值域为[0,prime-1]。
位运算Hash
这类型Hash函数通过利用各种位运算(常见的是移位和异或)来充分的稠浊输入元素。比如,标准的旋转Hash的布局如下:
staTIc int rotaTIngHash(String key, int prime)
{
int hash, i;
for (hash=key.length(), i=0; i
hash = (hash《《4》》28)^key.charAt(i);
return (hash % prime);
}
先移位,然后再进行各种位运算是这种类型Hash函数的紧张特点。比如,以上的那段打算hash的代码还可以有如下几种变形:
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));
信息安全
在信息安全领域中运用的Hash算法,还须要知足其他关键特性:
单向性(one-way),从预映射,能够大略迅速的得到散列值,而在打算上不可能布局一个预映射,使其散列结果即是某个特定的散列值,即布局相应的M=H-1(h)不可行。这样,散列值就能在统计上唯一的表征输入值,因此,密码学上的 Hash 又被称为\"大众择要(message digest)\"大众,便是哀求能方便的将\"大众\公众进行\公众择要\公众,但在\"大众择要\"大众中无法得到比\"大众择要\"大众本身更多的关于\"大众\"大众的信息。
抗冲突性(collision-resistant),即在统计上无法产生2个散列值相同的预映射。给定M,打算上无法找到M',知足H(M)=H(M') ,此谓弱抗冲突性;打算上也难以探求一对任意的M和M',使知足H(M)=H(M') ,此谓强抗冲突性。哀求\公众强抗冲突性\"大众紧张是为了戒备所谓\"大众生日攻击(birthday attack)\"大众,在一个10人的团体中,你能找到和你生日相同的人的概率是2.4%,而在同一团体中,有2人生日相同的概率是11.7%。类似的,当预映射的空间很大的情形下,算法必须有足够的强度来担保不能轻易找到\"大众相同生日\"大众的人。
映射分布均匀性和差疏散布均匀性,散列结果中,为 0 的 bit 和为 1 的 bit ,其总数该当大致相等;输入中一个 bit 的变革,散列结果中将有一半以上的 bit 改变,这又叫做\公众雪崩效应(avalanche effect)\"大众;要实现使散列结果中涌现 1bit 的变革,则输入中至少有一半以上的 bit 必须发生变革。其本色是必须使输入中每一个 bit 的信息,只管即便均匀的反响到输出的每一个 bit 上去;输出中的每一个 bit,都是输入中尽可能多 bit 的信息一起浸染的结果。