树表的查找
复习
- 线性表查找的三种方法
-
顺序/折半/分块
-
折半:效率most,**but需要关键字有序,不适合链表**
-
插入删除操作不方便
若要对动态查找表(会进行插入删除的表)进行查找:
二叉排序树(二叉搜索树)是啥?
二叉树--------》对结点值的约束--------》二叉排序树
左子树上所有节点关键字**<=根节点关键字
右…>=**…
二叉排序树的结点类型声明:
typedef struct node{
KeyType key;//关键字项
InfoType data;//其他数据域
struct node*lchild,*rchild;//左、右孩子指针
}BSTNode;
和二叉链一样,通过根节点指针bt唯一表示二叉排序树
删除节点中用子结点上来替代的函数:
void Delet(BSTNode*&p){
BSTNode*q;
if(p->rchild==NULL){
q=p;
p=p->lchild;//用p的左孩子替代
free(q);//释放函数
递归找结点r 的最右下结点
void Deletel(){
if(r->rchild!=NULL)
Deletel(p,r->rchild);
....
}
删除有双分支的节点
- 用该节点的中序前驱/中序后继结点q的值替换p结点的值
- 即左子树中最右的叶节点/左子树中最左的叶节点
平衡二叉树的调整
LL型
- 调整前后对应的中序序列相同
- 向右旋转
LL型和RR型是对称的
RR型
- 向左旋转,左子树换位给旁边的
LR型和RL型是对称的
平衡二叉树中删除结点
查找—》删除—》调整
- 本来是一颗平衡的,所以平衡因子均正常
- 调整:从被删除的地方向根结点方向找第一个失去平衡的结点
-
-2:右边多了
-
-1:右边多一些,RR
-
1:左边多一些,RL
-
0:RR/RL都可
-
2:左边多了
-
-1:右边多一些:LR
-
1:左边多一些:LL
-
0:LL/LR都可
平衡二叉树的构造
Th以Th-1和Th-2作为其根节点的左右子树
对于每一个Th,只要从中删去一个结点,就会失去平衡或高度不再是h
平衡二叉树中结点个数与高度之间的关系
h=log2(Nh+1)
- 含有n各结点的平衡二叉树的平均查找长度为O(log2n)
- 算法的时间复杂度为O(log2n)
折半查找对行的判断树是一颗平衡的二叉排序树
==》时间复杂度也是👆
B树
用于:多路查找
B树的特点
- m阶==》每个节点至多m个孩子节点/m-1个关键字
- 叶子都在同一层
- 所有节点的平衡因子均为0
- m/2<=孩子节点<=m
- m/2-1<=关键字<=m-1
计算B树的高度时,需要计入最底层的外部结点
外部结点就是失败结点,指向它的指针为空
关键字与外部结点个数的关系
n个关键字–》n+1个外部结点
B树的结点类型定义
//链式
#define MAXM 19
typedef int KeyType;
typedef struct node{
int keynum;
KeyType key[MAXM];//存放关键字的数组从1开始
struct node *parent;//双亲节点指针
struct node *ptr[MAXM];//孩子节点指针数组[0....keynum]
}BTNode;
n:节点个数
p:节点i
k:节点上的关键字序列
B树的查找
将k与根节点中的key[i]进行比较
key[i]存放该节点的关键字k1,k2,k3…
查找失败:
找到某个节点相应的指针为空时–》落入了外部节点–》查找失败
(即:外部节点指针为空)
B-树的插入
只能是叶子节点的插入
1、查找该关键字的插入节点
2、插入关键字
思考:
1、不是
2、不是
B-树的删除
1、查找
2、删除关键字
删除非叶节点
中序前驱、中序后继上来替代它
删除叶节点
注意删除后,节点的关键字数需要满足min和max,所以可能需要调整
不够的话需要找【兄弟】借
删除后min不够的情况下:
👇
17双亲下来,18兄弟上去(15,17,18)
兄弟也不够借?
将双亲中的中间(分割他们的数)放下来,与被删除节点和兄弟节点合并
发现双亲节点也不满足了???
继续合并!
这种情况下,树的高度下降了一层
B+树
与上树的不同
1、有n颗子树的节点恰好有n个关键字【某个节点的子树和关键字的关系】
2、叶子节点包含全部关键字,指向相应记录的指针
3、叶子节点按照关键字大小顺序连接,并将叶子节点连接起来
4、每一个分支节点向下,包含的是子节点中【最大关键字】及指向子节点的指针
类似下级索引的索引块
B+树的查找
一、通过【根节点】指针【随机查找】
二、通过【叶子节点】指针【顺序查找】
哈希表
适合什么?
关键字key和存储地址存在某种函数关系
学生信息问题
复习:查找方法:
- 顺序查找
- 二分查找
搞了一个函数关系之后(学号和存储地址的关系):
哈希冲突
关键字K1和k2不同,但函数值相同(地址相同)
不可避免
哈希表设计
哈希函数的构造方法
1、直接法
2、除留余数法
h=k mod p(p是素数,p<=m,存储空间m个单元)
3、数字分析法
- 关键字范围较大时
- 取最后两位为哈希地址
- 将大数值范围映射成小数值范围
哈希冲突解决办法
1、开放定址法
找个旁边的空位坐下
1)线性探查法
挨个往后找
2)平方探测法
找前后的空位置
可以避免堆积现象
开放地址法用哈希表查找k过程
- 调用哈希函数求出d=h(k),地址
- 该地址处的元素不是要找的
-
用某种探查法求处下一地址(因为存进去的时候不一定是按函数值
- if下一地址没有这个元素
-
查找失败
- 否则 有这个元素
-
该地址上的值即是所求
拉链法查找k过程
- 根据函数求地址d=h(k)
- 设一个指针p指向ha[d],ha[d]是一个单链表
- 判断d处的值是否=k
-
不相等:while循环下一节点p=p->next
- p为空时
-
查找失败
- 若找到了
-
返回p所指的节点
拉链法中成功查找的ASL计算
第i层节点个数*i之和
拉链法中不成功查找的ASL计算
- 只有1个节点的单链表有a个,即这a个都是只用比较一次就会失败
- 有2个节点的单链表有b个,即这b个都是只用比较一次就会失败
查找小结
线性表查找
线性表的存储结构
线性表查找算法
顺序
折半
分块
掌握两个ASL
折半查找成功的最大比较次数:判断树的最大高度Log2(n+1)
可由log2(19+1)=5知答案
顺序查找和分块查找所需比较次数会更多!!
比较元素出现了2次47!
树表查找
二叉排序树
二叉树结构+BST特性=二叉排序树
确定一棵树:需要中序+后序/中序+前序
中序一定是按元素值排列的
平衡二叉树
二叉排序树+平衡特性=平衡二叉树
拉链法不会引起堆积,线性探测法易引起