查找的基本概念
- 基本概念
- 查找
- 查找表
- 关键字(唯一标识)
- 对查找表的常见操作
- 查找符合条件的数据元素——静态查找表
- 插入、删除某个元素——且也要进行操作a的(动态查找表)
- 评价指标
-
查找长度——需要比较的关键字次数
-
平均查找长度(ASL)
ASL的数量级反映了查找算法时间复杂度
-
顺序查找和折半查找
顺序查找
1. 顺序查找又称线性查找。
算法实现
从头到脚或从脚到头挨个找
适用于顺序表、链表,表中元素有序无序都ok
typedef struct{
ElemType *elem; //动态数组基址
int TableLen; //表的长度
}SSTable;;
int Search_Seq(SSTable ST,ElemType key){
ST.elem[0] = key; //“哨兵”
for(int i = ST.TableLEN;ST.elem[i] != key;--i); //从后往前找
return i; //若查找成功,则返回元素下标;若查找失败,则返回0
}
将ST.elem[0]称为“哨兵”。优点:Search_Seq内的循环不必判断数组是否越界
2. 查找效率分析:
ASL_成功 = (n + 1)/2
ASL_失败 = n + 1
时间复杂度都是O(n)
算法优化
若表中元素有序
- 当前关键字大于(或小于)目前关键字时,查找失败
- 优点:查找失败时ASL更少
- 用查找判定树分析ASL
- 一个成功结点的查找长度 = 自身所在层数
- 一个失败结点的查找长度 = 其去节点所在层数
- 默认情况下,各种失败情况或成功情况都等概率发生
若各个关键字被查概率不同
- 可以将被查找概率大的放在靠前位置
- 优点:查找成功时ASL更少
折半查找(二分查找)
适用范围:只适用于有序的顺序表。
算法思想
- 在[low,high]之间找目标关键字,每次检查mid = (low + high) / 2
- 根据mid所指元素与目标关键字的大小调整low或high,不断缩小low和high的范围
- 若low > high则查找失败
判定树
构造
- 有mid所指元素将原有元素分割到左右子树中
- 👩💻 右子树结点树 - 左子树结点数 = 0或1
特性
- 折半查找的判定树是平衡的二叉排序树(左<中<右)
- 只有最下面一层是不满的
- 若查找表有n各关键字,失败结点有n + 1个
- 树高h(不包含失败结点)
时间复杂度:O(log2n)
分块查找
又称“索引顺序查找”,数据粪块存储;块内无序,快间有序
算法思想
- 索引表中记录每个分块的最大关键字、分块的区间
- 先查索引表(顺序或这般)、再对分块内进行顺序查找
ASL
ASL = 查索引表的平均查找长度 + 查分块的平均查找长度
设n个记录,均匀分为b块,每块s个记录
顺序查找索引表:
当
时,
折半查找索引表
👩💻 对索引表进行折半查找时,若索引表中不包含目标关键字,则折半查找最终停在low>high,要在low所指分块中查找
🤔 若查找表是“动态查找表”,可以用链式存储来实现。