题目描述
知识点
二叉树的建立、二叉树的遍历
结果
实现
码前思考
- 这种题目我之前做了无数遍了,但是这次我再次做的时候还是有很多不太清楚的地方,这🧠它不管用呀。。。
- 我参照《算法笔记》上的写法,使用递归的方式来建树,递归函数的意义是获得前序遍历区间
[preL,preR]
和中序遍历区间[inL,inR]
所在的树的根结点。递归的边界就是当前的树是空树,也就是preL>preR
,或者inL > inR
(两者是等价的)。 - 注意,前序遍历,后序遍历,层序遍历是用于获取根结点的,而中序遍历是用于划分左右子树的!所以必须要有中序遍历,但是对于BST来说它是不需要中序遍历的,因为它自身的性质已经决定了左右子树在哪了。
代码实现
//数组下标从1开始好理解一些
#include "bits/stdc++.h"
using namespace std;
const int maxn = 30;
//共享数据结构要注意初始化
char pre[maxn];
char in[maxn];
struct node{
char data;
node* lchild;
node* rchild;
};
//封装建立一个结点的函数
node* newNode(char x){
node* Node = new node;
Node->data = x;
Node->lchild = NULL;
Node->rchild = NULL;
return Node;
}
//递归建树函数
node* create(int preL,int preR,int inL,int inR){
//如果该子树的大小小于等于0,说明是一棵空树
if(preL > preR){
return NULL;
}
int k;
//我们来寻找根结点
for(k=inL; k<=inR; k++){
if(in[k] == pre[preL]){
break;
}
}
node* root = new node;
root->data = in[k];
//开始创建左子树和右子树
int numLeft = k - inL;
root->lchild = create(preL+1,preL+numLeft,inL,k-1);
root->rchild = create(preL+numLeft+1,preR,k+1,inR);
return root;
}
void postOrder(node* root){
if(root == NULL){
return;
}
postOrder(root->lchild);
postOrder(root->rchild);
printf("%c",root->data);
}
int main(){
while(~(scanf("%s",pre+1))){
//从数组下标1开始
scanf("%s",in+1);
//收集长度
int preL = 1;
int preR = strlen(pre+1);
int inL = 1;
int inR = strlen(in+1);
//初始化一个空的根结点
node* root = NULL;
//开始递归建树
root = create(preL,preR,inL,inR);
//进行后序遍历
postOrder(root);
printf("\n");
}
return 0;
}
码后反思
- 递归函数的意义很重要,一定要理清递归函数的意义,即这个函数是用来干什么的,它的输入是什么,它的输出是什么,不能瞎写,瞎写很容易写错,函数使用意义的,一定要好好思考函数的意义!这里我就一开始忽视了
create
函数的意义了。 - 如果是给的后序遍历结果和中序遍历结果我们怎么写?
我们始终要记得后序遍历是为了提供根节点的,那么我们想想对于一个后序遍历序列,它的根结点在哪?没错,就是最后面。这样理清了思路,我们就可以依葫芦画瓢了。 - 在这里,我使用的是动态二叉链表实现二叉树,可能要涉及到内存的回收什么的。《王道》上面使用的是静态二叉链表,关于静态二叉链表可以看这里.
- 牛客上面还有更加简短的代码,它就没有建树了,我没仔细看,我先多题一解吧,一题多解后面再想。