首先我们要清楚的是,二叉树遍历的三种形式:
1.先(根)序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴ 访问根结点;
⑵ 遍历左子树;
⑶ 遍历右子树。
2.中(根)序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴遍历左子树;
⑵访问根结点;
⑶遍历右子树。
3.后(根)序遍历得递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴遍历左子树;
⑵遍历右子树;
⑶访问根结点。
既然根据一棵已经存储好数据而建立起的二叉树,能够有三种方式对其中存储的数据进行访问。那么我们是否能够根据这三种方式访问的结果来建立起一棵二叉树或者说是根据其中的两种遍历方式的结果,求解出另外一种遍历的结果呢?答案是肯定的,在这里,我们主要研究根据其中的两种遍历方式的结果,求解出另外一种遍历的结果
有这样的一道试题:
题目链接:POJ2255
题目描述:
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 13325 | Accepted: 8312 |
Description
D / \ / \ B E / \ \ / \ \ A C G / / F
Input
Output
Sample Input
DBACEGF ABCDEFG BCAD CBAD
Sample Output
ACBFGED CDAB这道题的题意很清晰,就是给定一棵二叉树的先序和中序遍历的结果,要求这棵二叉树后序遍历的结果。
那么我们根据以上二叉树遍历的几种情况描述进行分析:
首先我们定义两个字符数组分别存储二叉树的先序和中序遍历的结果:
const int maxn = 30;
char pre_str[maxn],in_str[maxn];
然后我们看先序遍历的结果,先序遍历是从根节点开始遍历的,那么我们可以从先序遍历的结果得到整棵树的根节点为pre_str[0],而后我们看中序遍历,中序遍历的遍历过程是左子树 → 根节点 → 右子树,那么我们根据先序遍历得到的整棵树的根节点,然后寻找根节点在中序遍历中的位置,那么在根节点左边的部分则是二叉树的左子树部分,右边的部分则是二叉树的右子树部分。我们可以声明两个字符数组将左右子树存储起来:
char left_tree[maxn],right_tree[maxn]; //分别用来存储"当前根"的左子树和右子树
那么找到了二叉树的左右子树部分之后,我们要开始确定树根的下一层,即此时根节点的左孩子和右孩子节点。我们在前面已经存好了整棵树的左右子树部分,那么为了方便我们首先建立起整棵树的左子树部分,也就是开始寻找根节点的左孩子节点。同样的,根节点的左孩子节点以下部分依旧是一棵以该节点为"根"的二叉树,那么我们依然可以按照确定主根节点的方式确定此时主根节点的左孩子节点:
root->lchild = Build_tree(pre_str,left_tree,root->lchild); //pre_str表示删除当前已经读取的"根"节点后保存的字符串
//left_tree表示当前"根"的左子树部分
然后重复当前动作,直到当前"根"左子树部分为空,那么再按照同样的方式寻找其右子树部分。
root->rchild = Build_tree(pre_str,right_tree,root->rchild);
如果当前"根"的左右子树部分均为空,那么表示当前"根"节点处理完毕,那么函数返回上一层,并带回当前"根"的地址,赋值给上一层的"根"节点的左孩子或者右孩子,这样的话,一层一层的"根"节点相互之间就有了联系,当整棵二叉树的左子树部分处理完毕之后,然后再按照同样的方式处理右子树部分,同样的一层一层遍历过去,从底层返回时一层一层的节点建立起联系。当右子树部分处理完毕之后,这样的话,表示我们已经把一棵完整的二叉树构建起来了。然后再将主"根"(即整棵二叉树的根)的地址返回主函数,调用后序遍历函数即可得出结果。
完整代码实现(C语言):
/*思路:先根据前序和中序遍历将整棵树一步步的建立起来
*然后再调用后序遍历函数输出相应结果即可
*/
/**
0MS
388KB
user: sunshine
time: 2016-03-09 20:28:59
*/
#include
#include
#include
#include
using namespace std;
typedef struct Bintree_node Node;
const int maxn = 30;
struct Bintree_node{
Node *lchild,*rchild; //定义二叉树的节点存储类型
char data;
};
Node *Init(Node *root,char _data){
root = (Node *)malloc(sizeof(Node));
root -> data = _data;
root -> lchild = NULL;
root -> rchild = NULL;
return root;
}
Node *Build_tree(char pre_str[],char in_str[],Node *root){
char left_tree[maxn],right_tree[maxn]; //分别用来存储"当前根"的左子树和右子树
root = Init(root,pre_str[0]);
for(int i = 0;pre_str[i]!='\0';i++){
pre_str[i] = pre_str[i+1];
}
int i = 0,j = 0;
bool tmp = false;
while(in_str[i]!='\0'){
if(tmp){
right_tree[j] = in_str[i];
j++;
i++;
}
else if(in_str[i] != root->data && !tmp){
left_tree[i] = in_str[i];
i++;
}
else{
tmp = true;
left_tree[i] = '\0';
i++;
}
}
right_tree[j] = '\0';
int len1 = strlen(left_tree),len2 = strlen(right_tree);
if(len1 > 0){
root->lchild = Build_tree(pre_str,left_tree,root->lchild); //pre_str表示删除当前已经读取的"根"节点后保存的字符串
//left_tree表示当前"根"的左子树部分
}
if(len2 > 0){
root->rchild = Build_tree(pre_str,right_tree,root->rchild);
}
return root;
}
void postorder(Node *node){ //后序遍历
if(node -> lchild){
postorder(node -> lchild);
}
if(node -> rchild){
postorder(node -> rchild);
}
printf("%c",node -> data);
}
int main(){
Node *root;
char pre_str[maxn],in_str[maxn];
while(scanf("%s %s",pre_str,in_str)==2){
root = Build_tree(pre_str,in_str,root);
postorder(root);
printf("\n");
}
return 0;
}
完整代码实现(C++语言):
/**
360MS
21192KB
user: sunshine
time: 2016-03-09 20:24:07
不明白为何同样做法,与C语言耗时和内存消耗相差甚大= =
*/
#include
#include
using namespace std;
class Node {
public:
char data;
Node *lchild, *rchild;
Node(char _data) {
data = _data;
lchild = NULL;
rchild = NULL;
}
~Node() {
if (lchild != NULL) {
delete lchild;
}
if (rchild != NULL) {
delete rchild;
}
}
void postorder() {
if (lchild != NULL) {
lchild->postorder();
}
if (rchild != NULL) {
rchild->postorder();
}
cout << data;
}
Node *build(const string &pre_str,const string &in_str,int len){
Node *p = new Node(pre_str[0]); //存储根节点
int pos = in_str.find(pre_str[0]); //寻找根节点在中序遍历中的位置
if(pos > 0){
p->lchild = build(pre_str.substr(1,pos),in_str.substr(0,pos),pos);
}
if(len - pos - 1 > 0){
p->rchild = build(pre_str.substr(pos+1),in_str.substr(pos+1),len-pos-1);
}
return p;
}
};
class BinaryTree {
private:
Node *root;
public:
BinaryTree() {
root = NULL;
}
~BinaryTree() {
if (root != NULL) {
delete root;
}
}
BinaryTree(const string &pre_str,const string &in_str,int len){
root = root -> build(pre_str,in_str,len);
}
void postorder() {
root->postorder();
}
};
int main() {
string pre_str,in_str;
while(1){
getline(cin,pre_str, ' '); //以' '作为终止符
getline(cin,in_str);
BinaryTree binarytree(pre_str,in_str,in_str.length());
binarytree.postorder();
cout << endl;
}
return 0;
}
如有错误,还请指正,O(∩_∩)O谢谢