散列表——理论

来源:互联网 发布:百度地图经纬度数据库 编辑:程序博客网 时间:2024/06/16 04:37

参考本书,第一遍看完对证明以及一些结论完全是一脸懵逼,于是又参考了《算法导论》,自己整理了一下知识:(对比两本书,明白两点,一、看英文定义才是王道; 二、没有那个智商就不要有那么强的求知欲)

散列表( hash table):

特点:

·不需要序的信息(这也是个缺点啊);

·对输入数据是否有序持怀疑,数组可代替AVL树;

·实际存储的关键字数组比全部的可能关键字总数要小,即N个关键字存储到M个空间也能找得到(N>M),散列可代替数组。

优: insertdeletesearch    只需O(1);

缺: 一些需要序的操作,如findMax等;

总起:  

以优点为希冀,则希望 存储空间 允许为每一个关键字(key) 保留一个位置,来  直接寻址(即 k放入槽(slot) k, 这样的是直接寻址表

(direct—address table),简单、快捷),但是 关键字的无限 以及 存储单元的 有限 形成矛盾,于是借助散列函数,k放入h(k),从而使得存储空间又关键字个数N》》》散列表大小m


这就会产生一个问题,必然有冲突啊,如何处理?如何保持速度?

一个是从源头用优秀的hash function (随机);

另一个是从结果解决冲突


解决冲突:

装填因子(load factor) α=n/m

链接法( (seperate chaining)):   

最简单 、α≈1、借助链表,同一hash值的key在一个链表里;

前提:假设为简单均匀散列(simple uniform hashing)

操作:

·insert(不在表内,即不需要先查找检验): O(1)       [插入到表的前端,由于新插入的元素最有可能不久又被访问]

·search(不理想): 与表长成正比

分析:函数计算O(1) 查找不成功 θ(1+α) /查找成功 θ(1+α) [平均访问1+α个节点]》》》查找是一个常数时间,而查找到以后的 insert和delete即为O(1);

·delete: O(1) [双向链:废空间;单链:则慢于查找]ps:前面那是书上的意思,但是我个人认为,如果位置不知道,不如用两个指针的单链查找,则二者皆为与表长成正比,单链又可节省空间。

缺点:借助了另一种数据结构(浪费空间) 且 新单元分配需要时间(new 节点);


开放寻址法(open addressing):

探测散列表(probing hash table) 、α<=0.5、由于不借助外部,则所有元素均分布在散表中,那么元素间则构成了一个探测序列(即一个有意无意间的排序);

前提:假设为均匀散列(uniform hashing)即探测序列有m!种 、 表大小为素数(一个不太接近2的整数幂的素数),否则

备选单元会过早用完;

操作:

·delete:是懒惰删除,否则不知道其后是否还有元素,不能给查找操作一个理由;

·search:理想情况下:期望探查次数: 成功 1/αln(1/(1-α));不成功 1/(1-α)


·线性探测(liner probing):【m种】

h(k,i) = (h'(k) + i) mod m ,(i = 0,1,2,...,m-1)

操作: 查找: 成功:1/2(1+1/(1-α)^2);不成功:1/2(1+1/(1-α))

缺点:一次聚集,平均查找时间越来越大,由于下一个被占用 (i+1)/m;


·平方探测(quadratic probing):【m种】

h(k,i) = (h'(k) + ci + c'i^2) mod m ,(i = 0,1,2,...,m-1) [ 实践首选 ]

操作:查找: 成功:1-ln(1-α)-α/2;不成功:1/(1-α)-α-ln(1-α)

缺点:二次聚集 所说的聚集,就是初始位置由于冲突都一样,然后后面的变化也一样,就决定了探查序列;

*素数大小的 m +⌈m/2⌉为空 = 总能插入新元素,当表太满时(时间长,易失败),可以:

再散列(rehashing):在原表的基础上,用新的hash function ,新表大小 为m*2后的附近素数

前提: ○表到一半满 ;○插入失败一次;○途中策略(middle-of-the-road strategy),即以α确定;


·双散列(double hashing):【m^2种】

h(k,i) = (h1(k) +i*h2(k)) mod m ,(i = 0,1,2,...,m-1) [ 理论首选 ]

h2(k)必须与m互素:取m为2的幂,h2为奇数;取m为素数,h2返回较m中的正整数,eg: = 1+k mod m’(m'为<m的素数); = m'- k mod m'

缺点:字符串这样的关键字,计算耗时;


散列函数:

要求:*近似满足均匀散列;*以自然数为基础计算 ( key>>>N);* 常数时间计算;

启发式:

除法散列法:h(k) = k mod m

乘法散列法:h(k) =⌊m( k A mod 1)⌋ (0<A<1,一般取黄金分割比0.6180339) [kA mod 1 为小数部分]

优点:对 m 无所谓,可以为 2^p ; 缩减空间、减小冲突


随机 : 随机冲突解决方案

全域散列法(universal hash functions):从一组精心设计的全域散列函数中,随机地选一个,计算关键字; k<>l时,两

者发生冲突的概率 <= 1/m;

 hab(k)=((ak+b)mod p)mod m (1<a<p-1;0<b<p-1;p:素数&关键字范围&p>m,p可选2^5-1、2^31-等)


其他:

(参考 《算法之美 隐匿在数据结构背后的原理》)

平方取中法: 先利用编码规则:k=》》标识符=》》内码=》》平方=》》取其中间的x位

优点:可产生伪随机数,故有较强的随机性; 适用于关键字码每一位都有重复出现的情况;

折叠法:移位 、分界


*著名散列函数:BKDR、RS、FNV (我不了解,就不逼逼了)


任何事情都有一个美好的期望:


完美散列(perfect hashing):

·两级散列方式(一级不存,若只有一个元素:a=b=0) + 全域散列 二者配合直至无冲突

·关键字时静态的

·search : O(1)

性质:

·二级散列表大小为 M = N^2 (1-》1 、 2-》4 、3-》9...);

·二级散列表大小期望值 <= 2N;

·二级散列表的存储总量 >=4N 的概率 <1/2;


新的散列算法:

(我没看太懂,尤其时后者,待明白了再更)

cuckoo hashingandhopscotch hashing


原理易,证明难,性质迷茫,不编程仿佛懂了,面对问题 :我可能学了假散列??!