查找算法
基本概念
查找表(数据结构),分为静态查找表和动态查找表
关键字:唯一标示某个记录的一个key,如数组的下标
ASL : $ASL=\sum_{i=1}^{n}P_iC_i$ ,其中Pi是概率,Ci是找到第i个数据元素需要比较的次数
顺序查找
查找成功:
查找失败:
一般线性表的顺序查找
设置哨兵:也就是在存储的时候将array[0]留空,然后就不需要在for中进行多余的判断
1 | struct SSTable |
有序表的顺序查找
由于线性表有序,因此,查找失败不需要比较到另一端,只需要比较到table[n] > key / table[n] < key即可,也就是假设比较等概率失败,那么概率为$\frac{1}{n+1}$
查找成功:$ASL=\frac{n+1}2$
查找失败:$ASL=\frac{n}2 + \frac{n}{n+1}$
折半查找
要求有序
查找成功:$ASL=log_2(n+1)-1$
分块查找
综合了顺序查找和折半查找的优点
分为索引表,以及查找表
索引表中的每个索引对应一个查找表,索引表有序,查找表可以有序,也可以无序
因此,ASL=索引表的ASL + 查找表的ASL
索引表可以使用二分查找,$ASL=log_2(b+1) + \frac{s+1}2$
B/B+树
B树又称为多路平衡查找树,要掌握!重点掌握
B树的特性如下
- 树中的每个节点至多有m棵子树
- 若根节点不是终端节点,则至少有两棵子树
- 除根节点以外的所有非叶节点至少有m/2棵子树
- 所有非叶节点的结构满足
- n为节点中的关键字数量,用来判断该节点所能容纳的关键字是否已满
- K为节点的关键字,满足
- P为指向子树的指针,且子树的所有节点小于
- 所有的叶节点都出现在同一层次上,并且不带信息
查找
B树的查找有如下步骤
- 在B树中找节点
- 在节点内找关键字,采用二分查找
- 如果查找失败,根据二分查找的失败条件,找到对应的子树,继续查找
插入
只能插入到叶节点中,如果为非叶节点,从根开始查找,直到查找到叶子节点,然后在叶子节点中插入
删除
删除规则如下:
- 如果关键字k在节点x中
- 如果x是叶节点
- 若x中的关键字个数>t-1,则删除k
- 若关键字个数=t-1
- 左右兄弟树的关键字个数>=t,则向相邻的节点树借一个节点,然后调整父母与子树的关系
- 若左右兄弟不够借,则合并左右兄弟和父母节点,成为新的子树
- 如果x不是叶节点,则做以下操作
- a:如果x节点中,前于的子树节点的关键字个数>t-1,则找出子树中的最大值,然后递归删除(使用删除规则)
- b: 如上,如果后于的子树节点的关键字个数>t-1,则找出子树的最小值,然后递归删除
- c:如果不满足a和b,且的关键字个数=t-1,则合并两棵子树
- 如果x是叶节点
1 | // C++ program for B-Tree insertion |
散列表
散列函数的构造方法:
- 除留余数法:假设hash map长度为m,取一个质数p<=m,index=key % p
- 数字分析法:
- 直接定址法:取线性函数,index=a*key + b
- 平方取中法:
- 折叠法
处理冲突的方法
开放定址法
公式为
- 线性探测法:$d_i=1,2,3,….m-1$,当冲突发生,寻找临近的单元,直到遍历整个表,这样会造成大量元素堆积
- 平方探测法:取$d_i=1^2,2^2,3^2,….(m/2)^2$,m必须是一个能表示成4k*3的质数
- 再散列法:发生冲突,在对其进行哈希
- 伪随机序列法:使用伪随机数
- 拉链法 :index对应链表,把所有index相同的值用链表存储起来,索引的时候找到链表然后再进行查找
字符串匹配
1.模式匹配
找到开头的字符串,然后再用一个指针继续匹配,匹配失败则返回开头,继续尝试寻找下一个开头
2.kmp
通过目标字符串构建状态数组
排序算法
算法的稳定性:如果两个相同的元素R1,R2,当排序之后不改变位置,那么则称排序稳定,否则称其为不稳定的
冒泡排序
冒泡算法让大的值下沉,小的值上升/小的值下沉,大的值上升
1 |
|
插入排序
插入排序将当前元素向左移动到合适的位置,此算法有两个循环
循环1:规定范围
循环2:移动数据
直接插入排序:边比较边移动
折半插入排序:先找到合适的位置,然后再移动
希尔排序
分治法,把数组分为多个,部分排序,然后整体排序
选择排序
选择最小的,移动到前面
堆排序
在构建堆时候,不断下沉
在插入堆的时候,上浮
快速排序
快速排序也属于分治的排序算法
先切分,切分的数据以切分的元素为界,左小右大/左大右小,然后对左右的切分数组再切分
1 |
|