查找
1.查找的基本概念
2.线性表的查找
- 顺序查找
- 折半查找
- 分块查找
3.树表的查找
- 二叉排序树
- 平衡二叉树
4.散列表的查找
- 散列表的基本概念
- 散列函数的构造方法
- 处理冲突的方法
- 散列表的查找
1.1查找的基本概念
查找表:同一类型的数据元素(记录)构成的集合
关键字:数据元素(记录)中某个数据项的值
(主关键字:关键字唯一地标识一个记录)(次关键字:关键字标识若干记录)
查找:根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素
动态查找表和静态查找表:若在查找的同时对表执行修改操作(插入或删除)称动态查找表,反之为静态查找表
平均查找值:为确定记录在查找表的位置,给定值需要对比关键字的次数
(基于线性表)
2.1顺序查找
查找过程:
从表的一端开始,依次将记录的关键字和给定值进行比较
🔵 : 适合使用顺序存储结构和链式存储结构
🔴:设置监视哨(在比较时,不需要判断关键字下标是否越界,大大提高时间效率)
2.2折半查找
折半查找也称二分查找
查找过程:
1.设区间下界为low,上界为high,找一个中间值mid,让给定值与中间比较
2.若给定值大于中间值,则舍弃[low,mid],从(mid,high]中重复步骤1
3.若给定值小于中间值,则舍弃[mid,high],从[low,mid)中重复步骤1
4.若给定值等于中间值,则查找成功
🔴:当在某一步中查找区间为空,则查找失败
算法:
- 每次舍弃一边区间时,在新的区间,需要high=mid-1(舍弃右半边)或者low=mid+1(舍弃左半边)
- 循环的条件是:while(low<=high)
- 中间值的取值:mid=low+(high-low)/2
2.3分块查找
分块查找又称索引顺序查找
查找过程:
1.先确定给定值所在的块(比较索引表的最大值),2.然后在该块中用顺序查找
设置块(子表)
需要创建一个索引表,将若干个元素分成几块,将各块的最大值存进索引表中并记录自身下标记录
3.1二叉排序树
3.1.1二叉排序树的性质:
1.若它的左子树不空,则左子树上的所有节点的值均小于它的根节点的值
2.若它的右子树不空,则右子树上的所有节点的值均大于它的根节点的值
3.它的左,右子树也分别为二叉排序树
🔴:中序遍历一颗二叉树可以得到一个节点值递增的有序序列
3.1.2二叉树的查找:
查找过程:
1.给定值等于根节点,则查找成功
2.给定值小于根节点,则递归查找左子树
3.给定值大于根节点,则递归查找右子树
3.1.3二叉排序树的插入
二叉排序树的插入操作是在查找的基础上完成的,而且新插入的节点一定是一个新添加的叶子节点,并且是查找不成功时查找路径访问的最后一个节点的左孩子或者右孩子(保证插入的值是原本二叉排序树不存在的)
算法:
1.若二叉排序树为空,则将待插节点*s作为根节点插入空树
2.若二叉排序树不为空,则和根节点比较
- 若给定值小于根节点,则插左子树
- 若给定值大于根节点,则插右子树
- 运用递归,直到插入成功
3.1.4二叉排序树的创建
二叉排序树的创建是从空的二叉排列数开始的,每输入一个节点,经过查找操作,将新节点插入当前二叉排序树的合适的位置上
算法:
1.将二叉排序树初始化为空树
2.读取一个关键字作为节点
3.如果读取的关键字不是结束标志,执行以下循环
- 将此节点插入二叉排序树(🔴:运用插入二叉排序树的规则 )
- 再读取一个关键字作为节点
3.1.5二叉排序树的删除
一共有三种情况:
1.删除的节点p仅有左子树
用p的左孩子来填补
2.删除的节点p仅有右子树
用p的右孩子来填补
3.删除的节点p即有左子树,又有右子树
在p的左子树用中序排序找到最后一个节点来填补(中序排序的结果得到一个单调递增的序列)
3.2平衡二叉树
3.2.1平衡二叉树的定义
平衡二叉树:
1.左右子树的深度之差的绝对值不超过1
2.左右子树也是平衡二叉树
该节点的平衡因子:定义为该节点左子树和右子树深度之差的值(仅可能是-1,0,1)
🔴当遇到多个失衡节点,调整最小失衡子树的根节点
3.2.2平衡二叉树的平衡调整方法
1.LL型
(在节点p的左子树的左子树插入新节点)
让节点p的左子树作为新的根节点,原本的节点p变成右子树
2.RR型
(在节点p的右子树的右子树插入新节点)
让节点p的右子树作为新的根节点,原本的节点p变成左子树
3.LR型
(在节点p的左孩子的右子树插入新节点)
将新插入的节点作为根节点,原本的节点p作为右子树
4.RL型
(在节点p的右孩子的左子树插入新节点)
将新插入的节点作为根节点,原本的节点p作为左子树
🔴:对于LR型,RL型,对于不平衡二叉树的连续的三个节点,需要寻找中间值作为根节点,这样才满足平衡二叉树的性质
4.1散列表的基本概念
散列表又称哈希表,通过访问key而直接访问存储的value值
- 关键字key和存储位置之间有对应关系,这种关系用一种映射函数来实现,我们可以将关键字key代入到函数来访问对应的value值
散列函数和散列地址:在记录的存储位置p和其关键字key建立一个确定的对应关系的函数H,称该函数H为散列函数,该地址p为散列地址
散列表:一个有限的连续空间,用以存储经过散列函数计算得到相应散列地址的数据记录(存储地址)
(用一维数组来实现散列表,散列地址为数组从1开始的下标)
冲突和同义词:对不同的关键字可以得到同一个散列地址,称这种现象为冲突,这些有相同函数的关键字,称作同义词
4.2散列函数的构造方法
-
直接定址法
-
除留余数法
-
随机数法
-
数字分析法
-
平方取中法
-
折叠法
对于直接定址法:
使用一个线性函数(优点:不会冲突,缺点:要占用连续空间,空间效率低)
对于除留余数法:
使用一个数p(小于散列表表长,且为质数),关键字除以数p,除后所得余数作为散列地址
4.3处理冲突的方法
4.3.1开发地址法
思想:当发生冲突时,采用合适的方法计算得到一个新地址,最后全部关键字都需要存储到散列表数组中
1.线性探测法:
将散列表看成一个循环表,当发生冲突时,从冲突地址的下一单元顺序寻找空单元,一直循环寻找
2.二次探测法:
当发生冲突时,加/减一个平方的数,得到新的地址
3.伪随机探测法:
随机产生一个数字序列,加上该数字序列中的数字
4.3.2链地址法
思想:把具有相同散列地址的记录放在同一地址之间(记录之间用链表来结合起来)
m个散列地址就有m个单链表
🔴:用数组将m个单链表表头指针存储起来,形成一个动态结构
4.4散列表的查找
算法:
1.给待查找的关键字key,根据创建表时的散列函数计算地址
2.若单元为空,则查找失败
3.若单元中元素为key,则查找成功
- 若单元还存在但未查找到,按照处理冲突的方法,计算下一个散列地址