1.散列是一种用于以常数平均时间执行插入,删除和查找的技术。
但是,那些需要元素间任何排序信息的操作将不会得到有效的支持。
2.散列函数
每个关键字被映射到从0到TableSize - 1范围内的某个数,并且被放到适当的单元中。
这个映射就叫做散列函数。好的散列函数应该是关键字均匀的分配到表中。
3.散列函数的选择
a.如果关键字是整数,一般做法是返回key mod TableSize
b.如果关键字是字符串,一种选择方法是将字符串中的字符的ASCII码值加起来。
4.当一个元素被插入处另外一个元素已经存在(即散列值相同),那么就产生一个冲突。解决冲突的方法有多种,常见的有:
a.分离链接法
b.开放定址法
5.分离链接法
将散列到同一个值的所有元素保留在一个链表中
6.开放定址法
当有冲突发生时,尝试选择另外的单元,直到找到空的单元为止。
开放定址法所需要的表要比分离链接散列用表要大。
7.开放定址法有冲突时,会尝试选择其他单元,选择规则是Hi(X) = (Hash(X) + F(i)) mod TableSize,且F(0) = 0
其中H0(X),H1(X),H2(X)就是相继被试选的单元。函数F就是冲突解决方法。
8.冲突解决函数F的选择一般有下面几种:
a.线性探测法,函数F是i的线性函数,典型的情形是F(i)=i.相当于逐个探测。
b.平方探测法,函数F是i的平方函数。流行的选择是F(i)=i^2。
c.双散列法,流行的选择是F(i)=i*Hash2(X),即将第二个散列函数应用到X并再距离Hash2(X), 2Hash2(X)等处探测。
9.线性探测法
缺点是:已占据的单元比较集中,查找到自由单元的时间会随着元素的增加而增加
10.平方探测法
平法探测就是冲突函数为2次函数的探测方法。它能消除线性探测中一次聚集问题。
缺点是,一旦表被填满超过一半,当表的大小不是素数时甚至表被填满一半前,就不能保证一次找到空单元了。
最多有表的一半可以用作解决冲突的备选位置。另外此种方法有2次聚集问题
11.双散列探测法
第二个散列函数选择的不好将是灾难性的,另外一个重要的点是要保证表的大小是素数,否则备选的单元就有可能提前被用完。
12.开放定址散列表中,标准的删除操作不能施行,因为相应的单元可能已经引起过冲突,元素已绕过它存在了别处。
13.再散列
对于平方探测的开放定址散列法,如果表的元素填的太满,那么操作的运行时间将开始消耗的过长,
且Insert操作失败的可能性也在增大。此时的解决方法是建立另外一个大约两倍大的表,同时使用
一个相关的新的散列函数,扫描整个原始散列表,计算每个元素的新散列值并将其插入到新表中。
整个操作称为再散列。
14.再散列的施行时机选择有三种策略
a.只要表满到一半就再散列
b.只要插入失败就再散列(比较极端)
c.途中策略,即当表到达某一个装填因子时再散列。
15.可扩散列
可扩散列应用于数据量太大以至于装不进主存的情况。可扩散列允许用两次磁盘访问执行一次Find操作。
16.散列表和二叉查找树对比:
a.散列表可以用来以常数平均时间实现Insert和Find操作,二叉查找树对应的这两项操作的平均时间界是O(log N)
b.使用散列表不能找出最小元素,无法支持排序。如果不需要有序的信息以及对输入是否被排序有怀疑,那么应该选择散列
17.散列的应用
a.编译器使用散列跟踪源代码中声明的变量,实际就是符号表。
b.应用于图论问题,因为图论问题中节点名字都是字符而不是数字。
c.应用于游戏逻辑,即变换表
d.在线拼写检验程序