参考课程是我高中信息竞赛邱老师的课程。
【给定二叉树遍历序列恢复二叉树】 https://www.bilibili.com/video/BV1hizCY1EeU/?share_source=copy_web\&vd_source=2c56c6a2645587b49d62e5b12b253dca
【给定二叉树序列恢复二叉树习题解答】 https://www.bilibili.com/video/BV1NUzCYBE6t/?share_source=copy_web\&vd_source=2c56c6a2645587b49d62e5b12b253dca
需要完整板子可以去我资料获取,我设定的0积分,如果还要花钱去B站私我。
树


树的存储

孩子表示法

双亲表示法

孩子兄弟表示法

二叉树遍历

模板 B3642 给定左右节点的二叉树构建
https://www.luogu.com.cn/problem/B3642



将根节点存在下标的位置,然后左右子节点就是RN和LN。
然后根节点的下标是1,那么其两个子节点就是BT1.RN,BT1.LN。
输入的时候只需要根据根节点的下标输入即可。
cpp
#include<bits/stdc++.h>
using namespace std;
struct Node{
int LN,RN;
};
Node BT[1000005];
int n;
void preOrder(int i){
//根左右
cout<<i<<" ";
//如果有左子树
if(BT[i].LN) preOrder(BT[i].LN);
if(BT[i].RN) preOrder(BT[i].RN);
}
void inOrder(int i){
//左根右
//如果有左子树
if(BT[i].LN) inOrder(BT[i].LN);
cout<<i<<" ";
if(BT[i].RN) inOrder(BT[i].RN);
}
void postOrder(int i){
//左右根
//如果有左子树
if(BT[i].LN) postOrder(BT[i].LN);
if(BT[i].RN) postOrder(BT[i].RN);
cout<<i<<" ";
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>BT[i].LN>>BT[i].RN;
}
preOrder(1);
cout<<endl;
inOrder(1);
cout<<endl;
postOrder(1);
cout<<endl;
}
二叉树的恢复
前+中 中+后都是可以的。

模板 P1030
https://www.luogu.com.cn/problem/P1030

输出的第一个一定是根,而能确定根的无非是前后序。
cpp
#include<bits/stdc++.h>
using namespace std;
string inOrder,postOrder;
void findPreOrder(string in,string post){
if(in.empty()) return;//如果string排完了就返回
char root=post[post.size()-1];//取根 根一定来自前序后序
cout<<root;//每次都输出自己,自己一定是子树的根 【根】
//按照根切割子树,在前后序找到左右子树然后递归
int t=in.find(root);//string是容器,可以用find
findPreOrder(in.substr(0,t),post.substr(0,t));//【左】
findPreOrder(in.substr(t+1),post.substr(t,post.size()-t-1));//【右】
}
void findPostOrder(string in,string pre){
if(in.empty()) return ;
char root=pre[0];
int t=in.find(root);
findPostOrder(in.substr(0,t),pre.substr(1,t));//【左】
findPostOrder(in.substr(t+1),pre.substr(t+1));//【右】
cout<<root;//【根】
}
int main(){
cin>>inOrder>>postOrder;
findPreOrder(inOrder,postOrder);
}
前序+后序的不唯一性 P1229
https://www.luogu.com.cn/problem/P1229

为什么前序+后序无法确定唯一的中序?
只有当二叉树中存在 "只有一个孩子的节点" 时,不确定性才会产生。
- 如果一个节点有两个孩子(左、右),那么在前序和后序中,这两个孩子的相对位置和父子关系是确定的,无法互换。
- 如果一个节点 只有一个孩子 ,我们无法仅凭前序和后序判断这个孩子是 左孩子 还是 右孩子。
就是左右根和根左右,如果左右只有一个人,你不知道这个人是左还是右。
DCE CED这种情况可以唯一恢复。即要求包夹的部分是顺序。

而 GIH HIG则不可以,H包夹的部分是逆序就会出现不知道左右子树哪边为空的情况。

那么判定条件就是看前后序相邻的逆序对了。
先把s1(先序)反转,然后一个一个扫描长度为二的子串,如果在s2(后序)也有,那么就*2.
cpp
#include<bits/stdc++.h>
using namespace std;
string s1,s2;
long long ans=1;
int main(){
cin>>s1>>s2;
reverse(s1.begin(),s1.end());
for(int i=0;i<s1.size()-1;i++){
if(int(s2.find(s1.substr(i,2)))!=-1){
ans*=2;
}
}
cout<<ans;
}
练习1 二叉树深度 P4913
https://www.luogu.com.cn/problem/P4913

cpp
#include<bits/stdc++.h>
using namespace std;
struct Node{
int RN,LN;
};
Node BT[1000005];
int n;
int Depth;
void dfs(int i,int d){
if(i==0) return;//叶子节点
Depth=max(Depth,d);
dfs(BT[i].LN,d+1);
dfs(BT[i].RN,d+1);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>BT[i].LN>>BT[i].RN;
}
dfs(1,1);
cout<<Depth;
}
二叉搜索树

二叉搜索树可以通过中序遍历:左根右 的次序完成从小到大的遍历
二叉搜索树的构建 递归建树
递归建树模板 P2171
https://www.luogu.com.cn/problem/P2171

cpp
int buildBST(int cur,int i,int depth){
if(cur==0){//如果当前节点是空的就放这里
Depth=max(depth,Depth);//记录最大树高
return i;
}
//否则 如果插入节点的值比当前节点的值大,向右递归
if(BST[i].val>BST[cur].val){
BST[cur].RN=buildBST(BST[cur].RN,i,depth+1);
//这里用BST[cur].RN接受是因为最后一层时,插入后必须连接上他的父节点才行。
//depth是继承上一个节点的,没有问题。
}else{
BST[cur].LN=buildBST(BST[cur].LN,i,depth+1);
}
return cur;
}
cpp
#include<bits/stdc++.h>
using namespace std;
struct Node{
int LN,RN;
int val;
};
int n;
Node BST[300005];
int Depth;
int buildBST(int cur,int i,int depth){
if(cur==0){//如果当前节点是空的就放这里
Depth=max(depth,Depth);//记录最大树高
return i;
}
//否则 如果插入节点的值比当前节点的值大,向右递归
if(BST[i].val>BST[cur].val){
BST[cur].RN=buildBST(BST[cur].RN,i,depth+1);
//这里用BST[cur].RN接受是因为最后一层时,插入后必须连接上他的父节点才行。
//depth是继承上一个节点的,没有问题。
}else{
BST[cur].LN=buildBST(BST[cur].LN,i,depth+1);
}
return cur;
}
void postOrder(int i){
if(i==0){
return;
}
postOrder(BST[i].LN);
postOrder(BST[i].RN);
cout<<BST[i].val<<endl;
}
int main(){
cin>>n;
int val;
cin>>BST[1].val;
Depth=1;
for(int i=2;i<=n;i++){
cin>>BST[i].val;
buildBST(1,i,1);//递归建树
}
cout<<"deep="<<Depth<<endl;
postOrder(1);
}