查找
基本概念
查找:在数据集合中寻找满足某种条件的数据元素的过程称为查找
查找表(查找结构):用于查找的数据集合称为查找表,它由同一类型的数据元素(或或记录)组成
关键字:数据元素中唯一标识该元素的某个数据项的值,使用基于关键字的查找,查找结果应该是
唯一的。
查找长度 :查找时对比关键字的次数
二叉树的前驱后继(重要):
1、由当前节点的左子树的最右节点,进行替代(前驱)
2、由当前节点的右子树的最左节点,进行代替(后继)
ASL 平均查找长度(重要)
折半查找效率分析,(二叉判定树也是一个平衡二叉树)
ASL成功:(1 * 1+2 * 2+3 *4+4 *4)/11=3
节点数 * 层数
ASL失败:(3 * 4 + 4*8)/12=11/3
节点数 (对比节点) * 层数 / 总共失败情况次数
散列表ASL
1、首先根据散列函数计算出,元素的位置和冲突的次数
2、然后根据冲突次数算出ASL成功,然后根据散列地址表进行找出ASL失败
注:
散列地址要画 一共11个格子(根据散列函数所得) 所以ASL失败后面要加几个多余的1
顺序查找
结构: 线性表(顺序表或者链表)
思想: 挨着一个一个的查询,直到找到想要的
代码实现:
折半查找
结构: 有序的结构,顺序表
思想: 根据存储的值都是有序的,寻找某个key值,每次都是对数组的中间值(数组中间下标值)进行对比大小,如果大于中间值那么下一次 进行对比中间值往后的元素,再一次对比后面的中间值 然后依次循环。 如果小于也同上。
代码实现:
分块查找
结构: 就是将一系列元素,逻辑上分为 一块一块的区间
分块优化,折半查找,最后是在low中进行查找。
二叉排序树
叶子结点:也叫终端结点,是度为 0 的结点。
最小不平衡树:就是找平衡因子大于|1|的,如果有多个,那么找某个树节点最少的。
二叉排序树 特性:就是遵循左小右大特点的二叉树
对于二叉树 中序遍历 可以得到一个有序的序列
节点的删除
分为三种:
1、删除左子树节点,那么将由删除的左子树节点的下面的左子树进行代替,如:上图删除70,那么68代替
2、删除右子树节点,同上,由删除的右子树下面的右子树进行代替
3、删除根节点,根节点有左右子树,
3.1、由当前节点的左子树的最右节点,进行替代(这根线索二叉树的 线索的前序和后序类似TODO手动去验证)
3.2、由当前节点的右子树的最左节点,进行代替
平衡二叉树(AVL)
术语
注意:一般考试为手算
简称平衡树(AVL树):树上任一结点的左子树和右子树的高度之差不超过 |1|
结点的平衡因子:左子树高-右子树高
平衡因子补充:要注意每次都是根据左右两个树的高度进行计算,而不是根据左右子树的平衡因子进行计算的
手算调整树插入的平衡(重要)
LL(左边平衡因子超过):进行右旋转操作(找到最小不平衡子树,将当前节点代替父节点,父节点变为当前节点的右子树,(原有节点)当前节点的右子树边为父节点的左子树。)
RR(右边平衡因子超过|1|):进行左旋操作(找到最小不平衡子树,将当前节点代替父节点,父节点变为当前节点的左子树,(原有节点)当前节点的左子树边为父节点的右子树。)
LR:左旋再右旋,从最下面开始旋转 注意
RL:右旋再左旋
示例练习:
1、插入90,导致二叉树不平衡,然后找到最小不平衡树为66这个树,然后分析得出为RR型,那么进行左旋操作
2、插入CL/CR导致不平衡,然后找最小不平衡树,为A,分析得出为LR,那么进行左旋+右旋
3、RL
平衡二叉树删除调整
找最小不平衡子树,就是从删除节点往上找。
1、删除55,出现不平衡的现象
2、找到儿子和孙子节点
3、调整完毕
示例:
1、删除32,导致不平衡,找到最小不平衡子树44,然后找到最大 子节点(78),孙子节点
(50),可以得出RL.,然后50右旋,后再进行左旋操作
2、删除75,首先根据二叉树删除规则,将75进行删除,由前驱或者后继进行代替,本次使用前驱,删除后,进行二叉树调整,发现此次为RR,因此将80进行左旋。
红黑树
考点: 红黑树的性质,红黑树的插入,一般代码还有删除不考(因为比较复杂)
特点:红黑树是二叉排序树的一种优化。
1、每个节点不是红色、就是黑色。
2、 根节点是黑色的。
3、 叶节点(外部节点、null节点)均是黑色的
4、 不存在两个相邻的节点都为红色的(红节点的父亲或者孩子都不可能是红色)
5、从一个根节点到达任意叶子节点,所经历的黑色节点都是相同的
左根右,叶路同,不红红,黑路同
性质1:从根节点出发,最长路径不大于最短路径的两倍
黑高:是指某个根节(不含本节点本身)点到达叶子节点黑节点的数量。
注意: 红黑树的叶子节点是指,失败节点
基本结构示意图
红黑树–插入
插入的策略:
插入根节点的时候为黑色,当插入非根节点就为红色 ,当不满足特性的时候,判断RR\LL\RL\LR是根据插入节点的爷节点进行判断的。
B树(概念着重,因为考过名词说明)
[m/2]向上取整: [5/2] =3
结点关键字: ([m/2]-1,m-1)
b树:即就是二叉排序树的扩展,二叉排序树一个节点只能有个子树,b树可以扩展为多个
特性1:b树同红黑树一样,最下层为叶子节点。叶子节点上面的称为终端节点
2、树中每个结点至多有m棵子树,即至多含有m-1个关键字。
3、若根结点不是终端结点,则至少有两棵子树。
4、除根结点外的所有非叶结点至少有 【m/2】棵子树,即至少含有【m/2】-1个关键字。
5、所有的叶结点(空节点)都出现在同一层次上,并且不带信息
n个关键字必定有n+1个叶子结点
b树的插入
如果是空树插入的话,都是从最底层一个节点开始,然后进行向上分裂
空树构造
视频参考
当一个节点的关键字满了之后是,去当前节点的中间值作为父节点([m/2]),然后选出当前节点是插入到父节点指针的右边
示例:
b树的删除
删除根节点
删除根节点:由删除节点的,直接前驱或者后继进行替代。(前驱和后继跟二叉树中的方式一样)。
前驱:找当前关键字 下面的左指针中最右下下的 元素
后继:找当前关键字 下面的右指针中最左下下的 元素
如:删除77,找后继为82
终端节点的删除
如果删除到当前节点不能满足,b树的特性那么将借用左右节点的关键字。当左右节点的关键字都不够的时候,那么进行合并 左or右节点,并且将父关键字一块合并
B+树
结点关键字:([m/2],m)
特性:
1、节点的子树个数 与关键字m相等(比较爱考因为可以跟b树区别,b树是m+1个树)
2、非叶根至少有两颗子树
3、只有叶子结点存储的是数据的指针和关键字信息,其他分支节点存储的是指向叶子结点指针只是一个索引的作用。
b+树查找的物理逻辑:
例如上图找42
首先根据磁盘上根节点(15,56)信息读取到内存中,找到如56,,然后再将子节点(35,42,56)56从磁盘读取到内存中,接着找(40,42)42结点,然后读取内存,接着从42中 关键字信息和数据指针信息进行读取记录数据中的内容到内存。(这就解释了为什么大多使用b+树来代替b树的原因之一,因为b树的话每个结点都存储大量的数据指针关键字之类的,这样使得查找数据比较缓慢,而b+树非跟叶子结点只存储叶子结点的位置索引。)
另一个原因,因为每个结点磁盘大小是有限的16kb,如果每个结点都存储关键字信息+指针信息,那么会导致结点的关键字变少,而关键字变少意味着树的高度就会增加,这样就会导致IO读取磁盘的次数变得更多cpu开销更大
在C中可以将上面的树形结构理解为【结构体+左指针+右指针+数组(关键字)】
b+树分支节点可能会有重复的关键字,但是b树种是没有重复的关键字
b+树叶子结点存储信息,b树每个结点都存储
b树b+树差异
任何一个节点的子树的高度都要一样。
散列表(哈希表)
散列表(哈希表,HashTable):是一种数据结构。特点是:可以根据数据元素的关键字计算出它在散列表中的存储地址
散列函数(哈希函数): Addr=H(key)建立了"关键字"→"存诸地址"的映射关系,如使用 取余的方式进行(5%10)
同义词: 表示两个关键字 首次 所计算的地址冲突了
散列函数
除留余数法(常考)
11%13 = 11
除留余数法:addr=key%p
注:质数又称素数。指除了1和此整数自身外,不能被其他自然数整除的数
余数p的取值:散列表表长为m,取一个不大于m但最接近或等于m的质数p
如:5就是质数、13也是质数(2例外,2是一个特殊的质数)
直接定址法
a,b都是自定义的一个常数
直接定址法:addr=key*a+b
特点:使用于关键字分布基本连续的情况下。
数字分析法
数字分析法–选取数码分布较为均匀的若干位作为散列地盘
如:如果要存储手机号,那么就直接使用手机号的后四位当做散列地址进行存储。
平方取中法
平方取中法–取关键字的平方值的中间几位作为散列地址。
特点:关键字的每位取值都不均匀
简化:关键字进行平方,平方后的值取中间的两位作为地址
处理冲突的几种方式
拉链法
声明:默认链表采用头插法
拉链法:如果散列表插入地址冲突,那么将会生成一个链表的方法进行存储冲突的数据。
查找长度
如:
1、寻找27的值,根据7%13得出地址1,然后对比79,27。查找成功,因此查找长度为 “ 2”
2、查找21的值,地址为:8,8没有值,发现查找失败,因此长度为“0”
3、查找66的值,地址为:1,1中对比4次,查找失败,因此长度为“4”
开放定址法
开放定址法:又分为4种,但是整体的思想都是如果冲突了之后,再给他另寻一个其他空闲的地址。
m:散列表的长度
addr=[(addr)+d] % m
线性探测法(常考)
注意:以下4种算法如果不论查找还是删除,在查找元素的时候如果遇到空单元,那么表示查找失败\删除失败
线性探测法:如果地址冲突,那么就依次往后面寻找空闲的位置。每次都+1的寻找,最多到m-1位置
平方探测法
平方探测法:如果冲突那么根据 i的平方的方式进行寻找空闲的位置,i依次累加,一正一负,先从正开始。可以直接从1²开始,不用理会图上的0.
注意:如果根据平方探测法查找,查找的过程中,发现一个空的单元,那么直接查找失败。
双散列法
双散列法:就是对 计算地址的方法使用两次,最终计算出空闲的地址。
H=(h(key)+d)%m
如:addr=key%13
要插入1的值,进行计算地址 1= 1%13,得出d=m-addr 即 12=13-1
addr=(冲突key+1*d) %13 — 0=(1+1 * 12)%13
12=(1+2 * 12)%13
11=(1+3 * 12)%13
伪随机序列法
伪随机序列法:跟线性探测法类似,就是线性探测增量值是依次累加的,而伪随机序列法增量值是由自己写代码随机生成的。
4种算法的删除注意
删除的时候不能直接物理删除,不然就可能导致,查找其他冲突元素的时候出现问题,因此删除的时候都是逻辑删除(flag=1)
查找(总结):
叶子结点:也叫终端结点,是度为 0 的结点。
红黑树中:最后一行为null,的为终端节点(叶子节点)也称失败节点,第一个为根节点,其他为分支节点(或非终端节点)
b树,b+树:关键字最后一行称为终端节点,最后一行关键字下一层都为null的称为 终端节点(叶子结点)
树调整:
当AVL/二叉树/b树删除节点进行补替的时候,可以选择 后继或者前驱 进行替换
找后继:当前节点右子树下面最左下节点
找前驱:当前节点左子树下面最右下节点
平衡二叉树
红黑树调整:
叔黑:LL\RR旋转+父爷变色,LR/RL 旋转+儿爷变色
叔红:旋转+叔夫爷变色,爷变新
b树与b+树:
最后一层为空的称为叶子节点。任何叶子节点都在同一层
b :(m/2-1,m-1),m+1棵树,n+1个叶子节点
b+: (m/2,m) ,最多m棵树
散列表
- 散列表的平均查找长度依赖于散列表的装填因子,而不直接赖于 m或者n
- 装填因子a越小越好,越大越容易冲突