数据结构第七章 查找
查找的基本概念
- 查找:在数据集合中寻找满足某种条件的数据元素的过程称为查找
- 查找表(查找结构):用于查找的数据集合称为查找表
- 静态查找表/动态查找表
- 关键字:数据元素中唯一标识该元素的某个数据项的值
- 平均查找长度(ASL):一次查找的长度是指需要比较的关键字次数,平均查找长度是指查找过程中进行关键字的比较次数的平均值
顺序查找和折半查找
顺序查找(线性查找)
对于顺序表和链表都适用,通常分为对一般无序的线性表和对按照关键字有序的线性表的顺序查找
- 一般线性表的顺序查找
基本思想:从线性表的一端开始,逐个检查关键字是否满足给定的条件
//一般线性表的顺序查找
typedef struct { //查找表的数据结构
ElemType *elem; //元素存储空间基址,建表时按照实际长度分配,0号元素留空
int TableLen; //表的长度
}SSTable;
int Search(SSTable ST,ElemType key) {
ST.elem[0] = key; //哨兵
int i;
for (i = ST.TableLen;ST.elem[i] != key;--i); //从后往前找符合条件的
return i; //如果表中不存在关键字为key的元素,将查找到i=0时,推出for循环
}
引入哨兵的原因:使得for循环不需要判断数组是否越界,避免很多不必要的判断语句
查找不成功的时候比较次数为n+1,ASL成功=(n+1)/2,ASL不成功=n+1;
当n较大时,平均查找长度较大,效率低;但是对数据元素的存储没有要求,对表中记录的有序性也没有要求,均可应用。对于线性的链表只能进行顺序查找。
- 有序表的顺序查找
ASL不成功=n/2+n/(n+1)
注意:顺序查找每个元素查找成功的比较次数只与其位置有关与是否有序无关,有序和无序查找成功的平均时间相同
折半查找(二分查找)
仅适用于有序的顺序表
基本思想:将给定key值与表中中间元素相比较,若相等,则查找成功,若不等则在前后半区域内进行重复操作
//折半查找
typedef struct {
ElemType * elem;
int TableLen;
}SqList;
int Binary_Search(SqList l, ElemType key) {
int low = 0;
int high = l.TableLen - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (l.elem[mid] == key)
return mid;
if (l.elem[mid] < key)
low = mid + 1;
else
high = mid - 1;
}
return -1; //查找失败
}
折半查找的过程可以用判定树来描述,判定树是一棵平衡二叉树
查找成功的ASL=log(n+1)-1;
树高h=log(n+1)
时间复杂度为O(logn),仅适用于顺序存储结构,不适用于链式存储结构,且要求元素按关键字有序排列
分块查找(索引查找)
既有动态结构有适于快速查找
基本思想:将查找表分成若干块,块内元素可以无序,但是块之间的元素必须有序,第一个块中的最大关键字要小于第二个块中的所有记录的关键字,以此类推。建立索引表,包含每块的最大关键字和各块中第一个元素的地址,按照关键字有序排列。
练习
//写出折半查找的递归算法,初始调用时,low=1,high=ST.length
//折半查找算法的递归实现,初始时low=1,high=ST.length
typedef struct {
ElemType* elem;
int length;
}SST;
int Search(int low,int high,SST ST ,int key) {
//low = 1;
//high = ST.length;
if (low > high)
return 0;
int mid = (low + high) / 2;
if (ST.elem[mid] == key)
return mid;
if (ST.elem[mid] > key)
Search(low, mid - 1, ST, key);
else
Search(mid + 1, high, ST, key);
}
线性表中个节点的检索概率不等时,可以用如下策略提高顺序检索的效率:若找到指定的结点,则将该节点和其前驱结点(若存在)互换,使得经常被检索的结点尽量位于表的前端,是设计在顺序结构和链式结构的线性表上实现上述策略的顺序检索算法
//顺序结构上的实现
typedef struct {
ElemType* elem;
int length;
}STT;
int Search2(int low, int high, ElemType key, STT ST) {
for (int i = 1;i <= ST.length;i++) {
if (ST.elem[i] == key&&i>=2) {
ST.elem[0] = ST.elem[i];
ST.elem[i] = ST.elem[i - 1];
ST.elem[i - 1] = ST.elem[0];
return i-1;
}
}
}
//链式存储方式再思考一下
B树和B+树
B树及其基本操作
B树,又称多路平衡查找树,树种所有结点的孩子个数的最大值称为B树的阶
B树是所有节点平衡因子都等于0的多路平衡查找树
B树的插入、删除、查询操作都要会做
B+树的基本概念
🐖:课后题目(计算)有很大的问题
散列表
散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数
散列表:根据关键字而直接进行访问的数据结构,建立了关键字和存储地址之间的直接映射关系
- 直接定址法:适用于关键字的分布基本连续,若不连续且空位较多则造成存储空间的浪费
- 除留余数法:最简单最常用
- 数字分析法:选取数码分布较为均匀的若干位作为散列地址,适用于已知的关键字集合
- 平方取中法:取关键字的平方值的中间几位作为散列地址,适用于关键字的每位取值不够均匀或小于散列地址所需的位数
处理冲突的方法
- 开放地址法:线性探测法、平方探测法、再散列法、伪随机序列法
- 拉链法