散列表

有许多涉及散列表的数据结构可用作索引,如:主存数据结构的散列表,在这种结构中有一个散列函数h,它以查找键(散列键)为参数并计算出一个介于0到B-1的整数,其中B是桶的数目。桶数组,即一个序号从0到B-1的数组,其中包含B个链表的头,每一个对应于数组中的一个桶。如果记录的查找键为K,那么我们通过将该记录链接到桶号为h(k)的桶表中来存储它。
辅助散列表:
桶数组有存储块组成而不是由指向链表头的指针组成。通过散列函数h散列到某个桶加溢出块的链以存放更多的记录。
注意:每个存储块的右端都有一个小方块,这个小方块表示存储块块头中附加的信息。我们将用它来连接溢出块,我们用它来保留存储块的其他重要信息。
散列表的插入:
当一个查找键为K的新纪录需要被插入时,我们计算h(k)。如果桶号为h(k)的桶还有空间,我们就把该记录存放到此桶的存储块中或在其存储块没有存储块链上的某个溢出块中。如果桶的所有存储块中没有空间,我们就增加一个新的溢出块到该桶的链上,并把新纪录存入该块。
散列表的删除:
删除查找的键值为K的记录与插入操作的方式相同。我们找到桶号为h(K)的桶且从中搜索查找键为K的记录,继而将找到的记录删除。如果我们可以将记录在块中移动,那么删除记录后,我们可选择合并同一链上的存储块。

静态散列表:桶的数目B从不改变。
动态散列表:它们允许B改变,使B近似于记录总数除以块中能容纳的记录数所得到的商;也就是说,每个桶大约有一个存储块。
动态散列表中比较常用的两种:可扩展散列表和线性散列表

可扩展散列表:
1、为桶引入了一个间接层,即用一个指向块的指针数组来表示桶,而不是用数据块本身组成的数组来表示桶。
2、指针数组能增长,它的长度总是2的幂,因而数组每增长一次,桶的数目就翻倍。
3、不过,并非每个桶都有一个数据块;如果某些桶中的所有记录可以放在以个块中,那么,这些桶可能共享一个块。
4、散列函数h为每个键计算出一个K位二进制序列,该k足够大,比如32.但是,桶的数目总是使用从序列第一位或最后一位算起的若干位,此位数小于k,比如说是i位。也就是说,当i是使用的位数是,桶数组将有2的i次方的项。
好处:
当查找一个记录时,我们总是只需要查找一个数据块。我们还需要查找到一个桶数组的项,但如果桶数组小到可以存放在主存中,那么访问桶数组就不需要进行磁盘IO。
缺点:
1、当桶数组需要翻倍时,要做大量的工作。这些工作会阻碍对数据文件的访问,或是使某些插入看来花费很长的时间。
2、当桶数翻倍后,它在主存中可能就装不下了,或者把其他的一些我们需要保存在主存的数据挤出去。其结果是,一个运行良好的系统可能突然之间每个操作所需磁盘IO开始大增。
3、如果每块的记录数很少,那么很有可能某一块的分裂比在逻辑上讲需要分裂的时间提前许多。

线性散列表:
1、桶数n的选择总是使存储块的平均记录数保持与存储块所能容纳的记录总数成义个固定的比例,比如80%。
2、由于存储块并不总是可以分裂,所以允许有溢出块,尽管每个桶的平均溢出块数远小于1.
3、用来作桶数组项序号的二进制位数是log以2为底n的对数向上取整,其中n是当前的桶数。这些位总是从散列函数得到的位序列的右(低位)端开始取。
4、假定散列函数值的i位正在用来给桶数组项编号,且有一个键值为K的记录想要插入到编号为a1、。。。ai的桶中;插入数设为m,如果m<n,则存在m桶,则直接插入。如果m>n,则m桶不存在,则将m存入桶 (m- (2的i次方))中
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值