1 查找的基本概念
概念
常见操作
评价指标
平均查找长度!!!!
✖前面表示长度 后边表示个数!
处于的是总共的紫色的个数
总结
2 顺序查找、折半查找、分块查找
2.1 顺序查找
适用于线性表!
正常代码
哨兵!代码
查找效率分析
成功的话是 求的平均值
失败的话就是 查找到0都没有对应相等的,所以就是查找了n+1次!
顺序查找的优化(对有序表)
有序表:查找表中的元素有序存放(递增/递减!)
写出查找判定树 写出失败的那些框!
注意最后的两个n
有查找判别数分析ASL
顺序查找的优化2(被查概率不相等)
把概率大的放前面!
总结
时间复杂度都是o(n)
2.2 折半查找
实现思想
适用于 有序的顺序表!就是 二分法!
mid的值算出来如果是小数 就向下取整!
查找成功
在右边的时候更新时:low = mid+1
在左边的时候 high = mid-1
low = mid+1
这个时候high = low,如果所指和目标相等则查找结束!
查找失败
全面的都一样 到到low=high时,
mid = low = hight 此时mid的小于 目标值 一次low = mid+1
这是会出现low>height的矛盾 所以!算法结束!
代码实现
这个判断逻辑是按照 元素是升序排列的!降序类似但不一样哦 注意辨别!
查找效率分析【具体计算】
关键词对比!--擦护照效率
折半查找的判定树【时间复杂度】
用到的结论
左子树的结点个数一定小于等于右!!!
右子树比左子树只可能多一个结点!!!!!!
所以这种就不可能存在
折半查找的判定树 一定是平衡二叉树!
树高公式和完全二叉树的计算方法一样
向上取整!
失败结点的个数等于总结点+1
时间复杂度
总结
思考:
大多时候是高的但不是全部
2.3 分块查找
算法思想
low和high表示这个块的起始位置和结束位置!
例子
查找成功
查找失败
算法过程
在分块内顺序查找!
找在那个块是也可折半查找
eg1 :当目标在索引表关键字里时
eg2:当目标不在索引表关键字里时
最后会出现low>hight的结果折半查找结束,这是目标可能在 low所指的分块内!
low指向的比目标更大!!!!
上一步时low=high;这是如果所指关键字a<目标b: low = mid+1 这是low所指的关键字就比目标大了,所以在这个分块 // 如果所指关键字a>目标b:hight = mid-1 这时hight所指的块都比目标小 所以目标只能在low分块
综上所述,一定在low分块里!!!
eg3:找不到分块low
特例的查找效率分析(ASL)
1、顺序查找
7有两次:对比10 对比7 然后结束yigongliangc
13有三次: 对比10 对比20 然后进去 对比13 结束 一共3次!
2、折半查找
27:一定不是2!!!远远不够!!!很庞大的工程
查找失败更复杂!!!
通项的查找效率
顺序查找
求ASL最小的时候!!!
什么时候ASL最小呢?当分块有个,每个分块有个,可以得出此时的ASL等于
当
这与顺序查找的ASL相比已经好特别特别多了,
直接所有元素顺序查找 当n = 10000时平均ASL是5000!
折半查找【有个小印象就可以了!】
总结
思考
插入一个元素8会导致所有的元素向后移动!代价太大 所以可以用链式存储!
数据结构应该怎末设计?因该采取什么样的查找算法 都是需要大家按照现实遇到的需求做下的决定!!!
3 树形查找
3.1 二叉排序树(BST)【缩写注意!】
定义
中序遍历就是 左中右!可以写出递增的序列!
查找代码
普通代码
成功:
失败:
T = T->rchild会等于NULL 这是这个循环就结束了 返回NULL
加入递归代码
两个代码的空间复杂度
递归要使用函数调用栈 需要的大小 是树的高度!
插入
当T为NULL时说明找到了 应该插入的位置!
一定注意这个数BSTree是引用类型的!!!!
构造二叉排序树
删除
1、删除叶子结点
2、只有一个左子树或右子树
删完连起来就行
3、既有左子树又有右子树
!!!详情见 数据结构(5):树和二叉树-CSDN博客 中的6.2
50 的直接后驱是60 这个60肯定是右子树总最小的结点 而且一定没有左子树(因为一旦有左子树说明还有一个比它小!)
让60代替50 然后删除60 这个结点 因为原60 是在最左下的所以没有左子树,回到第二种情况了,删了之后连起来就行!
当有直接前驱也是一样的:直接前驱说明是左子树中最大的,一定没有右子树,替代50后还满足二叉排序树的原则,删原来的30 后 后面右子树的话直接连上即可没有就算了
查找效率分析
查找长度
对比:就意味着一次循环或者递归
查找成功
对比的次数不会超过二叉树的高度!
所以
的效率是最高的
查找失败
失败的时候空时不要对比的,只有和关键字比较的时候 加查找长度!!!!!
总结
3.2 平衡二叉树(AVL!)
上面的排序树的时候 知道越胖胖的效率越高 而平衡二叉树就是胖胖的!!!
平衡二叉树(AVL定义)
左右子树高度差不超过1!!
当保证是平衡二叉树是,二叉排序树的查找效率可以达到
插入
关键是如何插入一个结点 还能保持平衡!
调整的对象是“最小不平衡子树!”
如何调整最小不平衡子树
1、LL
三个子树高度一定全是H
这样才能保证LL插入后A变成 最小 不平衡 子树!why?可以假设:
AR是H+1时 LL插入 A 的左右子树 只差1还是平衡;AR是H-1 A就不平衡了直接
当BR=H+1时 A 直接就是不平衡的;当BR=H-1时,LL插入后 BL和BR相差2 则里插入点最近的不平衡点B就变成了最小不平衡子树 !!不是A了
调整目标
解决方法:右旋
2、RR
解决方法:左旋
12 代码
gf意思就是与前面连起来的那些树!
顺序:爹的左/后 孩子的左/右 孩子变爹!
3、LR
解决办法:左旋+右旋
4、RL
方法:右旋+左旋
汇总
练习:
1、
2、
3、
查找效率
递推公式!!!
得到最少的结点 并且左右节点高度相差1
平均查找长度(ASL)
插入总结
删除
步骤
二叉排序树的删除满足了条件1!!!
例题
eg1 不需要调整
eg2
检查上面的结点是否因为这个而产生了不平衡的现象!!!
eg3
eg4 不平衡向上传导
eg5 删除时按照二叉排序
直接前驱和后继
前驱:从左孩子的右边一路向下!
删除之后:
删除总结:
3.3 红黑树(RBT)【no代码】(搜搜23年咋考的)
为什莫出现?
都在使用红黑树!!!!
所以重点就是定义、性质、手算插入!
定义
红黑树是二叉排序树!
5个要求
增加父节点指针!
顺口溜:
左<根<右
根叶黑:根节点和叶子结点是黑色的!
不红红:不存在相邻的红色结点!
黑路同:(一条路走到黑)从同一个顶点到任何一个叶子结点的过程中 路过的黑结点的个数相同!
例子:
叶子节点是失败的那种节点
出题思路:
黑高
根节点黑高是2
与“黑高”相关的推论:
满树--黑路通;所以最小的情况就是全黑的满二叉树!
就可以证明下方的性质2:
性质!!!!!!!!!![一定注意这个!]
2、
n个关键字!
红黑树的查找效率不会超过红黑树的高度 所以反映了
时间复杂度
查找
插入!!
AVL(平衡二叉树的插入!)
找到位置---最小平衡子树---旋转--使其重新平衡
策略:
父亲的兄弟就是叔叔!
旋转是一样的!
插入的非根结点染红是为了满足 黑路同 这个特性!
动谁染谁 往相反的方向染!
会破坏的只有“不红红”!!!
。。。。。。
。。。。
最后的结果:
插入总结:
红黑树对于左右子树的要求没有那麽严格!
删除
我真服了啊啊啊啊啊啊啊!没事哒没事哒没事哒!
时间复杂度!O(log_2(n))
3.4 B树
人如其名......
查找例子1【成功】
“走左边!”的感觉
当叉数比较多的时候!
查找例子2【失败】
如何保证查找效率
策略:
根节点是例外!!!!
策略2:
B树定义【满足两个策略】
高度都相同就是绝对的平衡。。。。
失败的结点还是叫叶子节点!
核心性质!!!!【选择】:
B树高度:
排除叶子节点!
最小高度:
最大高度:
高度越大说明 每个结点半酣的关键字和分叉尽可能的小
下边这个好理解一点哦
总结:
插入的时候根节点全凭运气,所以不一定整整好在那个范围里!
B树的插入:
一直插插插到超过时进行:
在这个基础上插一定插到最底层:
再插插插超过的话:
中间的那个元素插入到父节点里!
再插插插:
提出去的那个元素应该插入父节点的位置是 箭头链的那个位置!
再插插插:
父节点!超过!!
总结插入:
B树删除:
再非终端节点:
最左子树最右下的就是直接前驱,用这个替代!
把删除非终端转换成删除终端!
也可以使用直接后继:
用82顶替77
再删:
删38 之后低于下限了
兄弟够借的时候:
只有这样才能表示才能保证B树的特性不变(就是那个大小顺序!)
再删:
删90的时候
再删:
兄弟不宽裕 就两个人合体 删49
当兄弟没钱的时候总结:
插入和删除总结:
3.5 B+树【概念性的】
和分块查找很类似
保存每一层最大的关键字!
满足的条件
2)当根节点不是叶子的时候,那么他至少有 m/2 向上取整棵 子树!
3)第3个和B树是很不一样的,容易出选择题:再B树中 两个关键字就会有3个分支!而在B+树中分支【子树】树和关键字的个数相同!
4)叶子结点包含所有的关键字!!!还有指向记录的指针
B+树的查找
从根节点逐层向下
必须到最下面才查找结束!!!
但是B树就不用查找到最后一层!!
顺序查找
B树 vs B+树
不要求的内容:
只有放进内存里才有会进行读!
一个一个结点都存储在磁盘里,当这个关键字不存储对应的存储地址时,他的size就更小更方便,那么就会有更多的数据存储在磁盘里!
这就是B+和B最本质的区别!
总结:
4 散列查找
4.1 定义
4.2 处理冲突的方法-拉链法
小优化:
查找
对比关键词的次数才算到查找长度里!
平均查找长度ASL
成功:
失败:
装填因子
装的满不满的指标!
4.3 常见的散列函数【让冲突尽量减小提高查找效率!】
与质数相对的概念式合数!质数的因子只有1和自己
为什么一定要是质数?!
直接定址法:
不连续的话空位就很多
数字分析法:
平方取中法:
用空间换时间的算法
4.4 处理冲突方法2--开放定址法
线性探测法:
就是一个一个向后找直到有空的位置!
注意一个小细节!!!:
查找
同义词和非同义词都有可能发生冲突!!! 68 不是27的同义词但也被扫描了
这里的空位置算作一次比较次数,但是在处理冲突的方法1-拉链法里没有把与空算作一次对比,是因为那里的空位置存储的是一个空指针 不算;这里的空位置可以视为存储的是相同的数据类型的东西,因此算作一次次数!
删除
删除是要特别注意,要不然删了之后空了下次查找的时候就以为没有了,比如这个
解决方法:
删除的元素做一个标记 可以是一个bool型的变量 这样就可以让指针继续向下走了
查找效率分析(ASL):
成功:
就一个一个算.......
失败:
为什么?
同义词和非同义词堆积!
平方探测法
查找也是按照这个散列的序列
非重点小坑【探测到所有位置!】:
伪随机序列法
总结
开放定址法删除结点时要特别注意哦!!!
4.5 处理冲突法3-再散列法
王道上可能是错了