本文已参与「新人创作礼」活动,一起开启掘金创作之路。
查找算法的效率评价
查找成功的ASL
查找失败的ASL
顺序查找
- 算法思路:从头到尾或者从尾到头,逐个元素与哨兵比较
- 算法实现:引入0位置为哨兵可以减少一次越界判断;加入哨兵在第0的位置并存放要查找的元素,顺序查找的时候从后往前查找,所以就不用进行越界判断
- 无论如何优化都是O(n)
折半查找
- 算法实现:
- 缺点:要有序顺序表(链表不合适呀)
- 时间复杂度:log2n
查找判定树
- 构造
- 特性: 折半查找的判定树是平衡的二叉排序树 只要表中的关键字个数相同,就一定会生成形状相同的判定树 只有最下面一层不满 若有n个关键字,就要n+1个查找失败结点
分块查找
- 算法思想: 索引表中保存每块的最大关键字和分块存储空间
块内无序,块间有序 先在索引表中索引分块(可顺序,可折半) 然后在块内顺序查找
- 性能分析: ASL=查找索引表的ASL+查找分块的ASL
B树(多路平衡查找树)
- 满足以下性质: 1.每个结点至多m棵子树,至多m-1个关键字 2.若根结点不是终端结点,至少有两根子树 3.除根节点外,所有非叶结点至少有m/2下取整课子树,即至少含有m/2下取整-1个关键字 4.所有叶结点都在同一层次(每个节点的子树高度一致),叶节点不携带信息,类似于查找判定树的失败节点,实际上这些点不存在,指向这些节点的指针为空 一定是平衡的!,且关键字是排序的
- 高度: 高度不包括查找失败的叶子结点,就像上面所说,叶子结点实际上算是不存在的 最小高度:
最大高度:
- 插入 根本原则:除根节点之外,所有节点的关键字个数是xx~xx,且每个结点内部关键字有序
- 情况一: 若插入导致关键字书超过上限: 从中间位置分裂成两个部分,右边部分放在新节点中,左边部分放在源节点中,中点位置插入源节点的父节点;新元素一定是插入到最底层的终端节点,用查找来确定插入位置
情况二: 若导致父节点的关键字也超过上限:
- 删除:
- 情况一: 若被删除的关键字在终端节点: 删除后关键字个数未低于下限,直接删除; 低于下限: 右兄弟够借,用当前节点的后继,后继的后继依次顶替空缺; 左兄弟够借,用当前节点的前驱,前驱的前驱依次顶替空缺; 左右兄弟都不够借,与父节点内的关键字+左兄弟或者右兄弟(所以会产生不同的B树)进行合并,(父节点也要下来当儿子),若导致父节点关键字低于下限,需要继续合并(父结点的父结点下来当儿子)。
- 情况二: 若删除的关键字在非终端节点: 一定可以转化为终端结点删除; 用直接前驱或者直接后继来替代被删除的关键字,随后删除这个直接前驱或者直接后继。
B+树
- 满足以下性质
散列表
- 概念: 关键字通过hash函数与存储地址直接相关 不同关键字映射到同一个地址,这些关键字就是同义词 同义词的冲突叫冲突。 聚集(堆积):非同义词的冲突 装填因子(负载因子):表中记录数/散列表的长度;降低装填因子来减少冲突;直接影响散列表的查找效率(ASL)。 散列表中,ASL平均查找长度与装填因子直接相关,查找效率不依赖已有表项数目或表长。
- 处理冲突的方法
拉链法:
所有的同义词存储在同一个链表中 ASL:
对空节点的查找次数是0 冲突越多,查找效率越低,理想情况下时间复杂度可以是o(1) 链地址法不会产生堆积现象
开放地址法
线性探测法:
- 查找: 同义词和非同义词都要被检查; 空位置的判断也算作一次比较; 越早遇到空位就越早确定查找失败。
- 过程: hash一下后,一个一个往后查,查到空则停,但空位置也算一次比较
- 删除 不能简单地直接将被删除空间设置为空,否则会截断在它之后填入的同义词结点的查找路径,可以做一个“删除标记”进行删除标记
- 缺点 同义词与非同义词之间的冲突很容易造成聚集现象,影响查找效率
- ASL
平方探测法
- 过程 先hash一下,然后左右跳跃的查找,查到空则停。
- 优点 相比于线性探测更加不会产生聚集现象
再散列法
- 除了原始散列函数之外,多准备几个散列函数,当散列函数冲突时,用下一个散列函数计算一个新的地址,知道不冲突为止
伪随机序列法
- di是一个伪随机数
拉链法和开放地址法的ASL计算: ASL成功=(每个成功元素比较次数和)/元素个数 ASL失败=(每次hash失败比较次数和)/m 注意 :
- 拉链法的空不算比较次数,但开放地址的空还算一次比较次数(而且开放地址到空才停止)
- 失败的比较次数注意范围,到%m就可以了,因为%m后面不是每次hash能hash到的,只是散列表的长度而已。
- 分母m是模的值