Ⅰ 索树BST与平衡树Treap的区别,已经BST的基本功能介绍
二叉搜索树之:【二叉搜索树与平衡树的区别】【BST和treap的区别】_bei2002315的博客-优快云博客
Ⅱ 二叉搜索树的基本大纲
Ⅲ 二叉搜索树的建立
①基础版本建树也分两种形式:
❶ l [ ],r [ ]版本 ❷ node结构体版本
具体的应用在链接:
细节补充:
②此处是最基础版本的建树,因为是根据任意序列建树,
更详细的建树方式(根据某序列,比如前序,中序,后序),
以及三种节点生成方式的对比。 在链接:
二叉搜索树之:【中序遍历和前序遍历互帮互助建立BST】【Node 版本建树方式】【BST的两种存储节点的方式的对比】_bei2002315的博客-优快云博客
/*
根据给定任意的序列a[],建立一棵二叉搜索树
*/
#include <bits/stdc++.h>
using namespace std;
const int N=1010,inf=1e9;
int a[N];
int root,idx; //二叉树必备变量
struct Node
{
int l,r;
int key;
int siz;
}tr[N];
//BST标志性函数 1
int get_node(int key)
{
tr[++idx].key=key;
tr[idx].siz=1;
return idx;
}
//BST标志性函数 2
/*BST如果要维护子树的东西来更新每一个节点,比如siz,
就必须有这个标志性函数
*/
void pushup(int u)
{
tr[u].siz=tr[tr[u].l].siz+tr[tr[u].r].siz+1;
}
//建立空树
void build()
{
get_node(-inf),get_node(-inf);
root=1;
tr[root].r=2;
pushup(root);
}
void insert(int &u,int key) //与根节点不断比计较大小递归插入的过程
{
if(!u) //当前递归到的根节点u是空位,就把key插入
{
u=get_node(key);
}
else if(key<tr[u].key) //比根节点的数值小
{
insert(tr[u].l,key);
}
else if(key>tr[u].key) //比根节点的数值大
{
insert(tr[u].r,key);
}
else if(key==tr[u].key) //与根节点的数值一样大
{
return;
}
pushup(u);
}
int main()
{
int n;
cin>>n;
//step1:build()建立一棵空树
build();
//step2:读入序列
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
//step3:插入数据
for(int i=1;i<=n;i++)
{
insert(root,a[i]);
}
return 0;
}
Ⅳ BST的子节点变量维护 ,insert()已经把子节点维护的东西
初始化好了(联合pushup函数更新),相当于以前的siz[]数组用
dfs()初始化。
void pushup(int u)
{
tr[u].siz=tr[tr[u].l].siz+tr[tr[u].r].siz+1;
}
//建立空树
void build()
{
get_node(-inf),get_node(-inf);
root=1;
tr[root].r=2;
pushup(root);
}
void insert(int &u,int key) //与根节点不断比计较大小递归插入的过程
{
if(!u) //当前递归到的根节点u是空位,就把key插入
{
u=get_node(key);
}
else if(key<tr[u].key) //比根节点的数值小
{
insert(tr[u].l,key);
}
else if(key>tr[u].key) //比根节点的数值大
{
insert(tr[u].r,key);
}
else if(key==tr[u].key) //与根节点的数值一样大
{
return;
}
pushup(u);
}
Ⅴ BST的基本应用
①BST的深搜,用节点维护的信息(比如siz) 进行组合运算
(根据IV可知,每个节点的siz在建树操作的时候就已经初始化完成了)
比如说下面这道省赛题目:
Contest 1013 problem (csgrandeur.cn)
l 变量代表的是左子树的计算返回值
r 变量代表的是右子树的计算返回值
利用左右子树的计算返回值,计算出当前以u为根节点子树的计算返回值
并return 该值
这个部分与之前邻接表存储的深搜大不相同:
①之前用邻接表存储的,只需要计算 j =ne[i] 的单独 j 变量为根节点的子树的返回值
②此处存左右孩子的存储方式,要分别计算以左右孩子为根节点的子树的返回值,
用l,r分别表示这两个返回值
② BST的遍历之------已知前序遍历和后序遍历,求层序遍历
学习新的建树方式,类似于开两个数组 l[] , r[],存左右孩子
更完善的题解链接:
#include <bits/stdc++.h>
using namespace std;
const int N=40;
int postorder[N],inorder[N]; //定义后序遍历数组和中序遍历数组
int n; //点的数量
//l是指每个点的左儿子是谁,r是指每个点的右儿子是谁,pos是哈希表
unordered_map<int,int> l,r,pos;
/*
既然每次递归都要利用当前小序列的前序序列和后序序列,
所以参数存储(il,ir) -----中序序列的前后端点
(pl,pr) -----后序序列的前后端点
*/
int build(int il,int ir,int pl,int pr)
{
int root=postorder[pr]; //从后序序列中提取出根节点
int k=pos[root]; //从哈希表中找出root的位置
if(il<k) //说明左子树存在
l[root]=build(il,k-1,pl,k-1-il+pl); //根节点的左儿子应该是左子树去递归返回的根节点
if(ir>k) //说明右子树存在
r[root]=build(k+1,ir,k-1-il+pl+1,pr-1);
return root;
}
void bfs(int root)
{
queue<int> q;
q.push(root);
while(q.size())
{
auto t=q.front();
q.pop();
cout<<t<<" ";
if(l.count(t)) //如果t存在左孩子
{
q.push(l[t]);
}
if(r.count(t)) //如果存在右孩子
{
q.push(r[t]);
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>postorder[i];
}
for(int i=0;i<n;i++)
{
cin>>inorder[i];
pos[inorder[i]]=i;
}
int root=build(0,n-1,0,n-1);
bfs(root);
return 0;
}
③BST的特定序列(前中后)三种建树方式之:------------ l[ ],r[ ] 版本建树,和Node两种版本的建树
二叉搜索树之:【中序遍历和前序遍历互帮互助建立BST】【Node 版本建树方式】【BST的两种存储节点的方式的对比】_bei2002315的博客-优快云博客
④BST的任意序找某个节点的后继节点:---------------两种版本建树
二叉搜索树之:【实现找某个节点的后继】【二叉搜索树的性质】_bei2002315的博客-优快云博客
⑤BST中序遍历方式,之前学的是层序遍历,此处是中序遍历
二叉搜索树之:【中序遍历一棵二叉搜索树】【给一棵有固定形态的二叉搜索树填值】【用BST中序遍历的性质填值】【之前讲过层序遍历】_bei2002315的博客-优快云博客
⑥BST的深搜遍历方式---------从根节点到叶子节点的一条完整路径
二叉搜索树之:【深搜遍历二叉搜索树】【dfs】【了解二叉树深搜递归的边界:叶子节点(左右儿子都为空的是叶子节点)】【力扣上面类型题目写法的总结】_bei2002315的博客-优快云博客