数据结构7.docx
《数据结构7.docx》由会员分享,可在线阅读,更多相关《数据结构7.docx(19页珍藏版)》请在冰豆网上搜索。
数据结构7
第7章查找技术
7.1概述
7.1.1查找的基本概念
在查找问题中,通常将数据元素称为记录。
关键码
可以标识一个记录的某个数据项称为关键码,关键码的值称为键值。
查找
查找是在具有相同类型的记录构成的集合中找出满足给定条件的记录。
查找的结果
若在查找集合中找到了与给定值相匹配的记录,则称查找成功;否则,称查找不成功(或查找失败)。
静态查找、动态查找
不涉及插入和删除操作的查找称静态查找;涉及插入和删除操作的查找称动态查找。
查找结构
专门为查找操作设置数据结构,这种面向查找操作的数据结构称为查找结构。
7.1.2查找算法的性能
查找算法的时间复杂度是问题规模n和待查关键码在查找集合中的位置k的函数,记为T(n,k)。
将查找算法进行的关键码的比较次数的数学期望值定义为平均查找长度。
查找成功时,其计算公式为:
ASL
其中,n:
pi:
ci:
ci与算法密切相关,决定于算法;pi与算法无关,决定于具体应用。
如果pi是已知的,则平均查找长度ASL只是问题规模n的函数。
对于查找不成功的情况,平均查找长度即为查找失败对应的关键码的比较次数。
查找算法总的平均查找长度应为查找成功与查找失败两种情况下的查找长度的平均。
7.2线性表的查找技术
7.2.1顺序查找
顺序查找的基本思想为:
1.顺序表的顺序查找
顺序查找的一种改进算法:
设置“哨兵”。
哨兵就是待查值,将它放在查找方向的“尽头”,免去了在查找过程中每一次比较后都要判断查找位置是否越界,从而提高查找速度。
顺序查找算法:
时间性能分析:
·查找成功的情况:
·查找不成功的情况:
顺序查找的优点:
顺序查找的缺点:
如何改进:
7.2.2折半查找
折半查找要求线性表中的记录必须按关键码有序,并且必须采用顺序存储。
1.执行过程
例7-1在有序表{7,14,18,21,23,29,31,35,38,42,46,49,52}中查找关键码为14和22的记录。
⑴查找关键码为14的过程
7141821232931353842464952
⑵查找关键码为22的过程
7141821232931353842464952
2.非递归算法
设有序表的长度为n,待查值为k,折半查找的非递归算法如下:
3.递归算法
4.性能分析
用折半查找判定树描述查找过程。
下图是一个具有11个结点的判定树。
以深度为k的满二叉树(n=2k-1)为例,假设表中每个记录的查找概率相等,即pi=1/n(1≤i≤n),而树的第i层上有2i-1个结点,因此,折半查找的平均查找长度为:
所以,折半查找的平均时间复杂度为O(log2n)。
7.3树表的查找技术
7.3.1二叉排序树
二叉排序树又称二叉查找树,它或者是一棵空的二叉树,或者是具有下列性质的二叉树:
⑴若它的左子树不空,则
⑵若它的右子树不空,则
⑶它的左右子树也都是二叉排序树。
画出两个二叉排序树
classBiSortTree//本章假定记录中只有一个整型数据项
{
public:
BiSortTree(inta[],intn);//建立查找集合a[n]的二叉排序树
~BiSortTree();//析构函数,释放二叉排序树中所有结点,同二叉链表的析构函数
voidInsertBST(BiNode*root,BiNode*s);//在二叉排序树中插入一个结点s
voidDeleteBST(BiNode*p,BiNode*f);//删除结点f的左孩子结点p
BiNode*SearchBST(BiNode*root,intk);//查找值为k的结点
private:
BiNode*root;//二叉排序树(即二叉链表)的根指针
};
1.二叉排序树的插入
根据二叉排序树的定义,向二叉排序树中插入一个结点s的过程用伪代码描述为:
2.二叉排序树的构造
构造二叉排序树的过程是从空的二叉排序树开始,依次插入一个个结点。
设关键码集合为{63,90,70,55,67,42,98},从空树开始建立二叉排序树的过程。
构造一棵二叉排序树是不断地调用插入结点的算法而进行的。
二叉排序树的构造函数算法。
札记:
3.二叉排序树的删除
二叉排序树的删除操作要求:
首先,从二叉排序树中删除一个结点之后,要仍能保持二叉排序树的特性;其次,由于被删除的可能是叶子结点,也可能是分支结点,当删除分支结点时就破坏了二叉排序树中原有结点之间的链接关系,需要重新修改指针,使得删除结点后仍为一棵二叉排序树。
·在二叉排序树中删除值最小的结点。
首先找到这个结点,记作s。
删除s只需要简单地把s的父结点中原来指向s的指针改为指向s的右孩子。
这样修改指针,删除了s结点,且二叉排序树的特性保持不变。
·二叉排序树的删除。
不失一般性,设待删除结点为p,其双亲结点为f,且p是f的左孩子,则被删除结点有以下三种情况:
⑴p结点为叶子,p既没有左子树也没有右子树。
解决办法:
⑵p只有左子树pL或只有右子树pR。
解决办法:
⑶p既有左子树pL又有右子树pR。
解决办法:
综上,在二叉排序树中删除一个结点f的左孩子结点p的算法用伪代码描述为:
4.二叉排序树的查找及性能分析
由二叉排序树的定义,在二叉排序树中查找给定值k的过程是:
⑴若root是空树,则查找失败;
⑵若k=root->data,则查找成功;否则
⑶若k<root->data,则在root的左子树上查找;否则
⑷在root的右子树上查找。
上述过程一直持续到k被找到或者待查找的子树为空,如果待查找的子树为空,则查找失败。
二叉排序树的查找效率就在于只需要查找二个子树之一。
举例说明查找过程:
二叉排序树的查找算法。
7.3.2平衡二叉树
几个基本概念:
平衡二叉树
平衡二叉树或者是一棵空的二叉排序树,或者是具有下列性质的二叉排序树:
⑴根结点的左子树和右子树的深度最多相差1。
⑵根结点的左子树和右子树也都是平衡二叉树,
平衡因子
结点的平衡因子是该结点的左子树的深度与右子树的深度之差。
最小不平衡子树
最小不平衡子树是指以距离插入结点最近的、且平衡因子的绝对值大于1的结点为根的子树。
假设关键码集合为{20,35,40,15,30,25},在一棵空的二叉排序树上依次插入20、35和40的过程。
再插入15、30和25的过程。
·扁担原理:
·旋转优先:
设结点A为最小不平衡子树的根结点,对该子树进行平衡化调整归纳起来有以下四种情况:
⑴LL型
⑵RR型
⑶LR型调整
⑷RL型调整
7.4散列表的查找技术
7.4.1概述
散列的基本思想:
散列表:
散列函数:
散列地址:
散列过程为:
⑴存储记录时,通过散列函数计算记录的散列地址,并按此散列地址存储该记录。
⑵查找记录时,通过同样的散列函数计算记录的散列地址,按此散列地址访问该记录。
说明:
1.散列既是一种存储方法,也是一种查找方法。
2.散列技术的查找速度要比基于关键码比较的查找技术的查找速度高。
冲突:
同义词:
采用散列技术需要考虑的两个主要问题是:
⑴
⑵
7.4.2散列函数的设计
设计散列函数一般应遵循以下原则:
⑴计算简单。
散列函数不应该有很大的计算量,否则会降低查找效率。
⑵函数值即散列地址分布均匀。
函数值要尽量均匀散布在地址空间,这样才能保证存储空间的有效利用,并减少冲突。
几种常见的散列函数。
1.直接定址法
直接定址法的散列函数是关键码的线性函数,即:
H(key)=a×key+b(a、b为常数)
2.除留余数法
除留余数法的基本思想是:
选择某个适当的正整数p,以关键码除以p的余数作为散列地址,即:
如何选取p?
H(key)=keymodp
3.数字分析法
数字分析法根据关键码在各个位上的分布情况,选取分布比较均匀的若干位组成散列地址。
4.平方取中法
平方取中法是对关键码平方后,按散列表大小,取中间的若干位作为散列地址(平方后截取)。
5.折叠法
折叠法是将关键码从左到右分割成位数相等的几部分,最后一部分位数可以短些,然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。
通常有两种叠加方法:
⑴移位叠加:
将各部分的最后一位对齐相加;
⑵间界叠加:
从一端向另一端沿各部分分界来回折叠后,最后一位对齐相加。
7.4.3处理冲突的方法
1.开放定址法
用开放定址法处理冲突得到的散列表叫做闭散列表。
所谓开放定址法,就是由关键码得到的散列地址一旦产生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
⑴ 线性探测法
当发生冲突时,线性探测法从冲突位置的下一个位置起,依次寻找空的散列地址,即:
Hi=(H(key)+di)%m(di=1,2,…,m-1)。
设散列表表长为m,在线性探测法构造的散列表ht[m]上的查找算法用伪代码描述为:
当从闭散列表中删除一个记录时,有两点需要考虑:
⑴删除一个记录一定不能影响以后的查找;
⑵删除记录后的存储单元应该仍能够为将来的插入使用。
⑵ 二次探测法
当发生冲突时,二次探测法寻找下一个散列地址的公式为:
例:
关键码集合为{47,7,29,11,16,92,22,8,3},散列表表长为11,散列函数为H(key)=keymod11,用二次探测法处理冲突,得到的闭散列表
012345678910
Hi=(H(key)+di)%m(di=12,-12,22,-22,…,q2,-q2且q≤m/2)
⑶ 随机探测法
当发生冲突时,探测下一个散列地址的位移量是一个伪随机数列,即寻找下一个散列地址的公式为:
Hi=(H(key)+di)%m(di是一个随机数列,i=1,2,……,m-1)
2.拉链法(链地址法)
用拉链法处理冲突构造的散列表叫做开散列表。
3.公共溢出区
公共溢出区法的基本思想是:
例:
关键码集合{47,7,29,11,16,92,22,8,3},散列函数为H(key)=keymod11,用公共溢出区法处理冲突,构造的散列表(包括基本表和溢出表):
7.4.4散列查找的性能分析
影响冲突产生的概率有以下三个因素:
⑴散列函数是否均匀。
⑵处理冲突的方法。
⑶散列表的装填因子。
关于α: