B+树的基本概念
【应用】为数据库设计的一种B树的变形树
【定义】
一个m阶的B+树:
1. 每个分支结点至多有m棵子树(子结点)
1. 字和指向该子树的指针,不含有该关键字对应记录的存储地址(B树中结点还存储着对应磁盘页面的地址,便于从B树中找到结点后,从磁盘将该结点信息读入内存)
2. 在B+树中,叶结点包含了全部关键字,即在非叶结点中出现的关键字也会出现在叶结点中;而在B树中,叶结点包含的关键字和其他结点包含的关键字是不重复的。(其实这里的叶结点我的理解是终端结点)
散列表
【特点】根据关键字而直接进行访问的数据结构。通过散列函数
建立关键字和存储地址之间的一种直接映射关系。
【注】理想情况下,对散列表进行查找的时间复杂度为O(1),即与表中个数无关。但是难免存在要解决冲突的情况即多个key被映射到同一个地址。
冲突:散列函数可能会把两个或连个以上的不同关键字映射到同一地址
同义词:这些发生碰撞的不同关键字
【散列函数】
【要求】
1) 定义域必须包含所有关键字,而值域则依赖于散列表大小或地址范围。(可见允许多对一,毕竟内存资源是很宝贵的。)
2) 散列函数计算出来的地址应该等概率,均匀的分布在整个地址空间,从而减少冲突发生。
3) 散列函数应尽量简单,能够在较短时间内计算出任一关键字对应的散列地址。
【常用散列函数】
1. 直接地址法
直接取关键字的某个线性函数值为散列地址,散列函数为:
【特点】这种计算方法最简单,并且不会产生冲突(线性函数保证了关键字和地址的一一对应,主要是实际中a,b如何取值呢?)。它适合关键字的分布基本连续的
况,若关键字分布不连续,空位较多,将造成空间的浪费。
1. 除留取余法
这是一种最简单常用的方法。假定散列表长度为m,取一个不大于m但最接近或等于m的质数p,利用一下公式把关键字转换成散列地址。散列函数为:
【特点】除留取余法关键是选好p,使得每一个关键字通过该函数装换后等概率的(并不要求一一对应,因为取余法的定义注定会有冲突产生)映射到散列空间上的任一地址,从而尽可能的减少冲突。
2. 折叠法
将关键字分割成位数相同的几部分(最后一部分可以短一些),然后取这几部分的叠加作为散列地址,这种方法称为折叠法。
【特点】 关键字位数很多,而且关键字中每一位数字分布大致均匀,可以采用折叠法得到散列地址。
【处理冲突】
【引】应该注意到,任何设计出来的散列函数都不可能绝对的避免冲突,为此,必须考虑在发生冲突的时候应该如何进行处理。即为产生冲突的关键字寻找下一个空的hash地址。
假设已经选定散列函数H(key),下面用Hi表示发生冲突后第i次探测到的散列地址。
1. 开放地址法
【特点】 指的是可存放新表项的空闲地址既向它的同义词表项开放,又向它的非同义词表项开放(这就导致了空闲地址被争夺,进而引发次带影响)。其数学递推式:
式中,i=1,2…….,k(k < m-1);m表示散列表表长,为增量序列。
当选定某一增量序列后,其对应的处理方法是确定的。(也就是说是事先确定好了的)
1) 线性探测法:
【特点】 当=1,2,….m-1(相对递增值),称为线性探测法。 冲突发生时,顺序查看表中下一个单元(当探测到表尾地址m-1时,下一个探测地址是表首地址(通过递推式中取余来保证)),直到找出一个空闲单元(当表为填满时一定能找到一个空闲单元)或查遍全表
【分析】 线性探测法可能使第i个散列地址的同义词存入第i+1个散列地址,这样本应存入第i+1个地址元素就争夺第i+2个散列地址元素的地址…..从而造成大量元素在相邻散列地址上“聚集”(或堆积)起来,大大降低了查找效率。
2) 平方探测法
【特点】当=,,其中k,m必须是一个可以表示成4k+3的质数 ,又称二次探测法。
【分析】
平方探测法是一种较好的处理冲突的方法,可以避免“堆积”问题,(但还是 会有冲突出现,注意区分”冲突“和”聚集“)。它的缺点是不能探测到散列表上所有单元,但至少能探测到一半的单元。
【开放地址法—总结】
在开放地址法情况下,不能随便物理删除表中已有元素,因为若删除元素将会截断 起其他具有相同散列地址元素的查找位置。
如何去删除节点?
若必须在散列表中删除结点,则不能将被删结点的关键字置为NIL,而应该将其置为特 定的标记DELETED。因此须对查找操作做相应的修改,使之探查到此标记时继续探查下去。同时也要修改插人操作,使其探查到DELETED标记时,将相应的表单元视为一 个空单元,将新结点插入其中。这样做无疑增加了时间开销,并且查找时间不再依赖于 装填因子。同时在执行多次删除后,表面上看散列表很满,实际上有许多位置没有利用。因此需 要定期维护散列表,要把删除标记的元素物理删除(并且把后面的同义词 移到前面来)。
因此,当必须对散列表做删除结点的操作时,一般是用拉链法来解决冲突。
2.拉链法
【引】为避免非同义词发生冲突,可以把所有同义词存储在一个线性链表中,这个线性链表由其散列地址唯一标识。
【特点】散列地址为i的同义词链表的头指针存放在散列表的第i个单元,因而查找, 插入,删除操作主要在同义词链中进行。 拉链法适用于经常进行插入和删除的情况。
散列查找及性能分析 -----(适合查找)
【特点】散列表的查找和构造散列表的过程基本一致。
【执行步骤】
初始化:Addr=Hash(key)
1. 检测查找表中地址为Addr的位置上是否有记录,若没有记录,返回查找失败;若有记录,比较它与key的值,若相等,返回查找成功标志,否则执行步骤2;
2. 用给定处理冲突的方法计算“下一个散列地址”,并把addr置为此地址,转入步骤1
【性能分析】
散列表的查找效率取决于三个因素:散列函数,处理冲突的方法和装填因子。
装填因子:散列表的装填因子一般记为,定义为一个表的装满程度,即:
散列表的平均查找长度依赖于散列表的填装因子,而不直接依赖于n或m(是二者综合效果),直观来看,越大,表示填装的记录越满,发生冲突的可能性越大,反之则越小。
【小结】
虽然散列表在关键字与记录的存储位置建立了直接映像,但由于“冲突”的产生,使得散列表的查找过程仍然是一个给定值和关键字比较的过程(要顺着解决冲突的方式查找嘛)。因此,仍需以平均查找长度作为衡量散列表查找效率的度量(理想状态下是O(1),即关键字和地址一一对应)