第七章 查找
文章目录
7.1 查找的基本概念
查找表:是由同一类型的数据元素(或记录)构成的集合;
关键字:是数据元素(或记录)中某个数据项的值,用它可以表示一个数据元素(或记录);
主关键字:可以唯一地标识一个记录;此关键字:以识别若干记录的关键字;
查找:根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素;
动态查找表:在查找的同时能对表内数据进行操作的表;
静态查找表:只能查找不能操作的表;
平均查找长度:关键子个数的期望值(平均比较次数)查找算法时查找成功的平均查找长度,用ASL表示;
7.2 线性表的查找
7.2.1 顺序查找
顺序查找的过程:从表头的一端开始根据给定的值和表内的值进行比较,若相等则查找成功,反之则查找失败;
设置监视哨的顺序查找:在开始查找的表头的另一端设置监视哨,将需要查找的数据放入其中,若查找失败则返回监视哨的位序0;
优点:这个改进能使顺序查找在ST.length>=1000时,进行依次查找所需的平均时间几乎减少一半;
7.2.2 折半查找
折半查找也称二分查找:每次将待查记录所在的区间缩小一半;
算法描述:
用三个指针high,mid,low分别指向表区间的上界 中间位置和下界;
通过比较待查找数据元素的区间来移动指针再进行比较,直到比较完成或成功查找;
优点:效率高,比较次数少;
缺点:对表结构要求高,只能采用顺序表的形式;
7.2.3 分块查找
分块查找又称索引查找:需建立一个“索引表”,分区间,将区间内的最大关键字放入表中并填入起始地址;先确定待查记录所在的块,然后再块中顺序查找;
7.3 树表的查找
7.3.1 二叉排序表
1.二叉排序树的定义
- 若它的左子树不空,则左子树上所有结点的值均小于它根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它根结点的值;
- 它的左右子树也分别为二叉排序树;
性质:中序遍历二叉树时可以得到一个结点值递增的有序序列;
2.二叉排序树的查找
- 若二叉树为空,则查找失败,返回空指针;
- 若查找的关键字小于根结点的关键字,则递归查找左子树;
- 若查找的关键字大于根结点的关键字,则递归查找右子树;
平均查找长度:n+1/2;
3.二叉排序树的插入
新插入的结点一定时一个新添加的叶子结点;
- 若二叉树为空,则插入的元素为树的根结点;
- 若查找的关键字小于根结点的关键字,则将结点插入左子树;
- 若查找的关键字大于根结点的关键字,则将结点插入右子树;
4.二叉排序树的创建
- 将二叉排序树T初始化为空;
- 读入一个关键字为key的结点;
- 如果读入的关键字非结束标志,则循环执行以下操作:
- 将此结点插入二叉排序树T中;
- 读入一个关键字为key的结点;
5.二叉排序树的删除
假定:被删结点为p,双亲结点为f,PL和PR为左右子树;
- 若*p结点为叶子节点,直接赋予为空;f->lchild = NULL;
- 若*p结点只有左子树或PL只有右子树PR,则直接令PL或PR为 *p的双亲结点的左子树或右子树即可;
f->lchild = p->lchild(p->rchild); - 若*p结点的左子树和右子树均不空:
- 用*p的前驱(左子树中最大的元素)或后继(右子树中最小的元素)代替;
- 令*p的左子树接到其他结点的左子树上,右子树接到其他节点的右子树上;
7.3.2 平衡二叉树
1.平衡二叉树的定义
二叉树上结点的平衡因子定义为该结点左子树和右子树的深度之差,则平衡二叉树上所有结点的平衡因子只能是1,0,-1;
**平衡二叉树(又称AVL树)**的特征:
- 左子树和右子树的深度之差的绝对值不超过1;
- 左子树和右子树也是平衡二叉树;
2.平衡二叉树的平衡调整方法
找到离插入结点最近且平衡因子绝对值超过1的祖先结点,以该结点为根的子树称为最小不平衡子树;
LL型,LR型,RL型,RR型的调整方法都为将最小不平衡子树中最大的元素移到右子树,其次移到根结点,最小的移到左子树;
7.3.3 B-树
7.3.4 B+树
7.4 散列表的查找
7.4.1 散列表的基本概念
散列查找法(杂凑法或散列法):对元素的关键字值进行某种运算,直接求出元素的地址,即使用关键字到地址的直接转换方法,而不需要反复比较;
优点:查找效率高; 缺点:空间效率低
散列函数和散列地址:在记录的存储位置p和关键字key之间建立一个确定的对应关系H,使p = H(key),称这个对应关系H为散列函数,p为散列地址;
散列表:一个有限连续的地址空间,用以存储按散列函数计算得到相应散列地址的数据元素;
冲突:对不同的关键字可能得到同一散列地址的现象;
同义词:具有相同函数值的关键字;
7.4.2 散列函数的构造方法
- 直接定址法:Hash(key)=a.key + b;一次函数
优点:以关键码key的某个线性函数值为散列地址,不会产生冲突;
缺点:要占用连续空间,空间效率低; - 数字分析法:若数字较多或较大,则取用后四位数字来进行存储;
- 平方取中法:若不知道关键字的分布且位数不是很大,则将数字进行平方取中间的数字进行存储;
- 折叠法:若散列地址的位数较少,而关键字的位数较多,且难于直接从关键字中找到取值较分散的几位,将关键字从左到右分割成位数相等的几部分(注意最后一部分位数不够时可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位(舍去进位)作为散列地址。
- 除留余数法:H(key) = key % p;所得的余数为散列地址;
关键:选取适当的数p(不大于表长的数);
7.4.3 处理冲突的方法
1.开放地址法
基本思想:把记录都存储在散列表数组中,当某一记录关键字key的初始散列地址H0=H(key)发生冲突时,以H0为基础,采取适合方法计算得到另一个地址H1,一次得到另一个地址直到将关键字存储进去;
- 线性探测法
- 二次探测法
- 伪随机探测法
2.链地址法
基本思想:把具有相同散列地址的记录放在同一个单链表中,称之为同义词链表;
优点:非同义词不会冲突,无“聚集”现象;
链表上结点空间动态申请,更适合表长不确定的情况;
7.4.4 散列表的查找
给定关键字key,根据创建散列表的散列函数计算H0 =H(key)查找,直到查找成功;
小结:散列表技术具有很好的平均性能,优于一些传统的技术;
链地址法优于开地址法;
除留余数法作散列函数有欲其他类型函数;