二叉树遍历(数组和结构体建图,实现翻转等操作)

玩转二叉树

L2-011 玩转二叉树 (25 分)

题意:

给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数

数组代码:

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=35;
int ino[N],pre[N],tr[1<<(N/2)];
vector<int> v;
int n,num=1;

void build(int l,int r,int rt){
    if(l>r){
        tr[rt]=-1;
        return;
    }
    tr[rt]=pre[num++];
    //int k=int(find(ino+1,ino+n+1,tr[rt])-ino);也可以
    int k=int(find(ino+l,ino+r+1,tr[rt])-ino);
    build(l,k-1,rt<<1);
    build(k+1,r,rt<<1|1);
}

void lev(int rt){
    queue<int> q;
    q.push(rt);
    while(!q.empty()){
        int t=q.front();q.pop();
        v.push_back(tr[t]);
        //注意用tr[t<<1]还是t<<1,区分开
        if(~tr[t<<1|1])q.push(t<<1|1);
        if(~tr[t<<1])q.push(t<<1);
    }
}

int main(){
    cin>>n;
    ff(i,1,n)cin>>ino[i];
    ff(i,1,n)cin>>pre[i];
    build(1,n,1);
    lev(1);
    for(int i=0;i<v.size();i++){
        if(i!=v.size()-1)cout<<v[i]<<" ";
        else cout<<v[i]<<endl;
    }
    return 0;
}

结构体代码:

#include<string>
#include<queue>
#include <iostream>
#include<algorithm>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;

const int maxn = 50;
struct node{
    int data;
    node *lchild,*rchild;
};
int n;//结点个数
int pre[maxn], in[maxn];

node* create(int preL, int preR, int inL, int inR){//建树板子 
    if(preL > preR) return NULL;//前序序列都没了,直接返回
	
    node* root = new node;
    root->data = pre[preL];
    int k;
    for(k=inL; k<=inR; k++)
    	if(in[k] == pre[preL])break;          
    int numLeft = k -inL;//左子树结点个数 
//    debug(numLeft);
    //前序:root , [preL+1,preL + numLeft] , [preL + numLeft+1,preR]
	//中序:[inL,k-1] , root , [k+1,inR] 
	
    root->lchild = create(preL+1, preL + numLeft , inL, k-1);
    root->rchild = create(preL + numLeft+1, preR, k+1, inR);
    return root;
}

void BFS(node* root){//层序板子
    queue<node*> q; 
	q.push(root);
    int num = 0;
    while(!q.empty()){
        node* now = q.front(); q.pop();
        printf("%d", now->data);
        if(++num < n) printf(" ");
        if(now->rchild != NULL) q.push(now->rchild);
        if(now->lchild != NULL) q.push(now->lchild);
    }
}

int main(){
    scanf("%d", &n);
    for(int i=0; i<n; i++)scanf("%d",&in[i]);
    for(int i=0; i<n; i++)scanf("%d",&pre[i]);   
    node* root = create(0, n-1, 0, n-1);
    BFS(root);
    return 0;
}

完全二叉树的层序遍历

L2-035 完全二叉树的层序遍历 (25 分)

思路:

建树,然后遍历即可,建树方式不唯一

代码:

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=35;
int tr[1<<(N/2)],a[N];
vector<int> v;
int n,num,p=0;

void build(int rt){
    //如果这个点不在树上就返回
    if(rt>n)return;
//    错误示范
//    if(num<=0)return;
    tr[rt]=a[num--];
    build(rt<<1|1);
    build(rt<<1);
}

void lev(int rt){
    queue<int> q;
    q.push(rt);
    while(!q.empty()){
        int t=q.front();q.pop();
        v.push_back(tr[t]);
        if(~tr[t<<1])q.push(t<<1);
        if(~tr[t<<1|1])q.push(t<<1|1);
    }
}

int main(){
    memset(tr,-1,sizeof tr);
    cin>>n;
    num=n;
    ff(i,1,n)cin>>a[i];
    build(1);
    lev(1);
    for(int i=0;i<v.size();i++){
        if(i!=v.size()-1)cout<<v[i]<<" ";
        else cout<<v[i];
    }
    return 0;
}

因为是完全二叉树,层序遍历就很简单,简化版代码:

#include <iostream>
using namespace std;
int n, tr[31];

void build(int i) {
    if (i > n)return;
    build(2 * i);
    build(2 * i + 1);
    cin >> tr[i];
}

int main() {
    cin >> n;
    build(1);
    for (int i = 1; i <= n; i++) {
        if (i > 1)cout << " ";
        cout << tr[i];
    }
    return 0;
}

Invert a Binary Tree

1102 Invert a Binary Tree (25 分)

题意:

给你二叉树的节点信息,要你建图,求其翻转(存储的时候所有左右结点都交换)后的层序和中序遍历

注意点:

字符变成数字的时候要减去'0'

if(~p[t].r)if(p[t].l!=-1)是一个含义

单词解释:

  • level-order:层序
  • in-order:中序
  • post-order:后序
  • pre-order:前序

代码:

#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
//
const int N=15;
int n,have_fa[N];
vector<int> v1,v2;
struct node{
    int l,r;
}p[N];

void level_order(int rt){
    queue<int> q;
    q.push(rt);
    while (!q.empty()){
        int t=q.front();q.pop();
        v1.push_back(t);
        //这两种写法一个意思
        if(~p[t].r)q.push(p[t].r);
        if(p[t].l!=-1)q.push(p[t].l);
    }
}

void in_order(int rt){
    if(p[rt].r!=-1)in_order(p[rt].r);
    v2.push_back(rt);
    if(p[rt].l!=-1)in_order(p[rt].l);
}

int main(){
    cin>>n;
    f(i,0,n){
        char c1,c2;
        cin>>c1>>c2;
        if(c1!='-'){
            //作死示范
            //p[i].l=c1;
            p[i].l=c1-'0';
            have_fa[p[i].l]=1;
        }
        else p[i].l=-1;
        if(c2!='-'){
            p[i].r=c2-'0';
            have_fa[p[i].r]=1;
        }
        else p[i].r=-1;
    }
    f(i,0,n){
        //找到根节点
        if(!have_fa[i]){
            level_order(i);
            in_order(i);
            break;
        }
    }
    for(int i=0;i<v1.size();i++){
        if(i!=v1.size()-1)cout<<v1[i]<<" ";
        else cout<<v1[i];
    }
    cout<<endl;
    for(int i=0;i<v2.size();i++){
        if(i!=v2.size()-1)cout<<v2[i]<<" ";
        else cout<<v2[i];
    }
}

Tree Traversals

1020 Tree Traversals (25 分)

题意:

依次给出二叉树的后序和中序序列,构建二叉树,再对这个二叉树进行层次遍历

思路:

后序:左子树->右子树->根
中序:左子树->根->右子树

所以用后序的根分出这棵树的左右子树,再通过左子树的大小(左子树的节点个数)找到左子树的根,递归建树,之后bfs收尾

数组代码:

#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
//
const int N=32;
//tr数组其实要开大一些,在这里数据水了
int pos[N],ino[N],tr[1<<(N/2)];
int n,point;
vector<int> v;

void build(int l,int r,int rt){
    //子树为空,到叶子节点的左右节点了
    if(l>r){
        tr[rt]=-1;return;
    }
    int num=pos[point--];
    tr[rt]=num;
    int k=int(find(ino+l,ino+r+1,num)-ino);
    //由于"post[pos--]",下面2行不能交换,要把右子树重建再重建左子树,否则会段错误
    build(k+1,r,rt<<1|1);
    build(l,k-1,rt<<1);
}

void lev(){
    queue<int> q;
    q.push(1);
    while(!q.empty()){
        int t=q.front();q.pop();
//        错误示范
//        v.push_back(t);
        v.push_back(tr[t]);
        if(~tr[t<<1])q.push(t<<1);
        if(~tr[t<<1|1])q.push(t<<1|1);
    }
}

int main(){
    cin>>n;point=n;
    ff(i,1,n)cin>>pos[i];
    ff(i,1,n)cin>>ino[i];
    build(1,n,1);
    lev();
    for(int i=0;i<v.size();i++){
        if(i!=v.size()-1)cout<<v[i]<<" ";
        else cout<<v[i];
    }
}

结构体代码:

#include<string>
#include<queue>
#include<algorithm>
using namespace std;

const int maxn = 50;
struct node{
    int data;
    node *lchild,*rchild;
};
int n;//结点个数
int pre[maxn], in[maxn], post[maxn];

node* create(int postL, int postR, int inL, int inR){//建树板子 
    if(postL > postR) return NULL;//后序序列都没了,直接返回
	
    node* root = new node;
    root->data = post[postR];
    int k;
    for(k=inL; k<=inR; k++)
    	if(in[k] == post[postR])break;          
    int numLeft = k -inL;//左子树结点个数 
    //后序:[postL,postL + numLeft -1] , [postL + numLeft,postR-1] , root
	//中序:[inL,k-1] , root , [k+1,inR] 
    root->lchild = create(postL, postL + numLeft -1, inL, k-1);
    root->rchild = create(postL + numLeft, postR-1, k+1, inR);
    return root;
}

void BFS(node* root){//层序板子
    queue<node*> q; 
	q.push(root);
    int num = 0;
    while(!q.empty()){
        node* now = q.front(); q.pop();
        printf("%d", now->data);
        if(++num < n) printf(" ");
        if(now->lchild != NULL) q.push(now->lchild);
        if(now->rchild != NULL) q.push(now->rchild);
    }
}

int main(){
    scanf("%d", &n);
    for(int i=0; i<n; i++)scanf("%d",&post[i]);    
    for(int i=0; i<n; i++)scanf("%d",&in[i]);
    node* root = create(0, n-1, 0, n-1);
    BFS(root);
    return 0;
}

当然数组也可以从1存数据:

代码(结构体):

#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
//
const int N=35;
int post[N],ino[N],n;
vector<int> v;
struct node{
    int x;
    node *lc,*rc;
};
node* build(int lp,int rp,int li,int ri){
    //注意返回空的特点
    if(lp>rp)return nullptr;
    node* root=new node;
    root->x=post[rp];
    int k;
    for(k=li;k<=ri;k++)
        if(ino[k]==post[rp])break;
    int num= k - li;
    root->lc=build(lp, lp + num - 1, li, k - 1);
    root->rc=build(lp + num, rp - 1, k + 1, ri);
    //别忘记return,否则段错误
    return root;
}
void lev(node* root){
    queue<node*> q;
    q.push(root);
    while(!q.empty()){
        node* now=q.front();q.pop();
        v.push_back(now->x);
        if(now->lc!=nullptr)q.push(now->lc);
        if(now->rc!=nullptr)q.push(now->rc);
    }
}
int main(){
    cin>>n;
    ff(i,1,n)cin>>post[i];
    ff(i,1,n)cin>>ino[i];
    node* root=build(1,n,1,n);
    lev(root);
    for(int i=0;i<v.size();i++){
        if(i!=v.size()-1)cout<<v[i]<<" ";
        else cout<<v[i];
    }
}

Tree Traversals Again

1086 Tree Traversals Again (25 分)

题意:

给你二叉树的前序,中序遍历,输出其后序遍历

代码(数组求解):

#include<bits/stdc++.h>
using namespace std;
const int N = 32;
const int M = 1e5;//题目不严谨,随便开的
int midt[N];
int pret[N];
int dt[M];
int pri = 1, n;
queue<int>q;

void rebuild(int l,int r,int rt){
    if(l>r){
        dt[rt]=-1;
        return ;
    }
    int root=pret[pri++];//这里pri++就能做到在前序遍历中找到对应的根节点
    dt[rt]=root;
    int m=find(midt+l,midt+1+r,root)-midt;
    //下面2行不能交换,要把左子树重建再重建右子树,否则会段错误
    rebuild(l,m-1,rt<<1);		//重建左子树 ,不包括中点(根节点)
    rebuild(m+1,r,rt<<1|1);		//重建右子树 ,不包括中点(根节点)
}

void postorder(int rt){//后序遍历正确写法
    static int cnt=0;
    //到叶子结点的左右节点就得停止啦
    if(dt[rt]==-1)return;

    postorder(rt<<1);//递归左子树
    postorder(rt<<1|1);//递归右子树
    if(++cnt<n)cout<<dt[rt]<<" ";
    else cout<<dt[rt];
}

/*
void postorder(int rt){//后序遍历正确写法2
    static int cnt=1;
    if(dt[rt<<1]!=-1)postorder(rt<<1);//递归左子树
    if(dt[rt<<1|1]!=-1)postorder(rt<<1|1);//递归右子树
    cout<<dt[rt];
    if(cnt++ < n)cout<<" ";
}
*/

/*后序遍历错误示范
void postorder(int rt){
	static int cnt=0;
	if(rt>n)return;
	postorder(rt<<1);
	postorder(rt<<1|1);
	if(++cnt<n)cout<<dt[rt]<<" ";
	else cout<<dt[rt];
}
*/

/*层序遍历
void bfs(){
	int rt=1;
	q.push(rt);
	while(q.size()){
		int now=q.front();
		q.pop();
		if(dt[now]!=-1){//到叶子结点就得停止啦
			if(now!=1)cout<<" ";
			cout<<dt[now];
			q.push(now<<1);	    //先把左子树加入队列
			q.push(now<<1|1);	//再把右子树加入队列

		}
	}
}
*/

int main(){
    cin>>n;
    int t;string s;
    stack<int> st;
    int n1=0,n2=0;
    for(int i=0;i<2*n;i++){
        cin>>s;
        if(s=="Push"){
            scanf("%d",&t);st.push(t);
            pret[++n1]=t;
        }
        else{
            int k=st.top();
            st.pop();
            midt[++n2]=k;
        }
    }
    rebuild(1,n,1);
    postorder(1);
    puts("");
    return 0;
}

当然也可以全程vector模拟数组来做,代码如下(数组求解):

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=35;
int tr[1<<(N/2)];
int n,num=1;
vector<int> v1,v2,v3;

void build(int l,int r,int rt){
    if(l>r){
        tr[rt]=-1;
        return;
    }
    tr[rt]=v1[num++];
    //注意find函数范围
    int pos=int(find(v2.begin()+0+l,v2.begin()+0+r+1,tr[rt])-v2.begin());
    //题目比较水,像下面这么写也对,但不严谨
    //int pos=int(find(v2.begin(),v2.end(),tr[rt])-v2.begin());
    build(l,pos-1,rt<<1);
    build(pos+1,r,rt<<1|1);
}

void postorder(int rt){
    if(tr[rt]==-1)return;
    postorder(rt<<1);
    postorder(rt<<1|1);
//    错误示范
//    v3.push_back(rt);
    v3.push_back(tr[rt]);
}
int main(){
    //默认数组从1开始,0位随便赋一个值即可
    v1.push_back(-1);v2.push_back(-1);
    cin>>n;
    stack<int> st;
    f(i,0,2*n){
        string s;int t;
        cin>>s;
        if(s[1]=='u'){//先序
            cin>>t;
            v1.push_back(t);
            st.push(t);
        }
        else{//中序
            v2.push_back(st.top());
            st.pop();
        }
    }
    build(1,n,1);
    postorder(1);
    for(int i=0;i<v3.size();i++){
        if(i!=v3.size()-1)cout<<v3[i]<<" ";
        else cout<<v3[i];
    }
    return 0;
}

Structure of a Binary Tree

1159 Structure of a Binary Tree (30 分)

代码:

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=1e7+5,M=35;
int pos[M],ino[M],tr[N];
map<int,int> mp,dep;
int n,num;

void build(int rt,int l,int r,int d){
    if(l>r){
        tr[rt]=-1;return;
    }
    tr[rt]=pos[num--];
    mp[tr[rt]]=rt;
    dep[tr[rt]]=d;
    int p=find(ino+l,ino+r+1,tr[rt])-ino;
    build(rt<<1|1,p+1,r,d+1);
    build(rt<<1,l,p-1,d+1);

}

int con(string s){
    int res=0;
    f(i,0,s.length()){
        res=res*10+s[i]-'0';
    }
    return res;
}

int main(){
    cin>>n;
    num=n;
    ff(i,1,n)cin>>pos[i];
    ff(i,1,n)cin>>ino[i];
    build(1,1,n,1);
    int que;cin>>que;
    int full=1;
    ff(i,1,n){
        int k=mp[pos[i]];
        if((tr[k<<1]!=-1 && tr[k<<1|1]==-1)||(tr[k<<1]==-1 && tr[k<<1|1]!=-1)){
            full=0;
            break;
        }
    }
    while(que--){
        int res=0;
        int t1,t2;
        string s1,s2;
        cin>>s1>>s2;
        //It is a full tree
        if(s1[0]=='I'){
            cin>>s1>>s1>>s1;
            if(full)res=1;
        }
        else{
            t1=con(s1);
            if(s2[0]=='a'){
                cin>>t2>>s1>>s1;
                //A and B are siblings
                if(s1[0]=='s'){
                    if(mp[t1]/2==mp[t2]/2)res=1;
                }
                //A and B are on the same level
                else{
                    cin>>s1>>s1>>s1;
                    if(dep[t1]==dep[t2])res=1;
                }
            }
            else{
                cin>>s1>>s1;
                //A is the left child of B
                if(s1[0]=='l'){
                    cin>>s1>>s1>>t2;
                    if(mp[t1]==mp[t2]*2)res=1;
                }
                else if(s1[0]=='r'){
                    //A is the root
                    if(s1[1]=='o'){
                        if(mp[t1]==1)res=1;
                    }
                    //A is the right child of B
                    else{
                        cin>>s1>>s1>>t2;
                        if(mp[t1]==mp[t2]*2+1)res=1;
                    }

                }
                //A is the parent of B
                else{
                    cin>>s1>>t2;
                    if(mp[t1]==mp[t2]/2)res=1;
                }
            }
        }
        if(res) cout << "Yes" << endl;
        else cout << "No" << endl;
    }
    return 0;
}

Cartesian Tree

1167 Cartesian Tree (30 分)

不知道为什么只有29分:

在这里插入图片描述

代码:

#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int inf=2e9,N=35;
map<int,pair<int,int>> mp;
int n;
int a[N];
int build(int l,int r){
    if(l>r)return -1;
    int rt=N,pos;
    ff(i,l,r){
        if(a[i]<rt){
            rt=a[i];pos=i;
        }
    }
    mp[rt].first=build(l,pos-1);
    mp[rt].second=build(pos+1,r);
    return rt;
}

int main(){
    cin>>n;
    ff(i,1,n){
        cin>>a[i];
    }
    build(1,n);

    int rt=N;
    ff(i,1,n)rt=min(rt,a[i]);
    queue<int> q;
    q.push(rt);
    int num=0;
    while(q.size()){
        int t=q.front();q.pop();
        cout<<t;
        if(++num<n)cout<<" ";
        if(~mp[t].first)q.push(mp[t].first);
        if(~mp[t].second)q.push(mp[t].second);
    }
    return 0;
}

别人的ac代码:传送门

希望大佬给出解答😭

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值