根据二叉树的前序(后序)和 中序确定一个二叉树并以层次遍历输出

这里只给出后序和中序确定二叉树的方法,前序和中序是差不多的;

先给出代码:


#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<map>
#include<sstream>
#include<vector>
#include<string>
#define MAXN 1000
using namespace std;

struct Node {
    int n;
    Node *left,*right;
    Node():left(NULL),right(NULL),n(-1) {}
};

Node *root;
int inO[1001],post[1001],cnt;

Node * newnode() { return new Node(); }

bool read_data(int *a) {
    string tmp;
    if(!getline(cin,tmp)) return false;
    stringstream s(tmp);
    cnt = 0;
    int x;
    while(s >> x) a[cnt++] = x;
    return true;
}

Node *buildtree(int *inO,int *post,int len) {
    if(len == 0) return NULL;
    Node *node = newnode();
    node->n = post[len - 1];
    int p = 0;
    for(; p < len ; ++p) {
        if(inO[p] == post[len - 1]) break;
    }
    node->left = buildtree(inO,post,p);
    node->right = buildtree(inO + p + 1,post + p, len - p - 1);
    return node;
}

void showtree(Node * root) {
    queue<Node*> qu;
    qu.push(root);
    Node *tmp;
    while(!qu.empty()) {
        tmp = qu.front();
        qu.pop();
        cout << tmp->n << " ";
        if(tmp->left != NULL) qu.push(tmp->left);
        if(tmp->right != NULL) qu.push(tmp->right);
    }
    cout << endl;
}

int main(void)
{
    memset(inO,0,sizeof(inO));
    memset(post,0,sizeof(post));
    while(read_data(inO)) {
        read_data(post);
        Node *root = buildtree(inO,post,cnt);
        showtree(root);
    }
    return 0;
}


先解释一下 <sstream> 这个头文件,更具体的可以自己百度学习一下,很有用; 这个头文件有一个 stringstream, 它的用处就是能把字符串中,为数字的部分转换为数字,比如 (string)ss123dd, 可以把其中123这个部分转换为数字,很方便,这里,这个代码是根据 UVA 548 改过来的,可以去了解一下,需要用到的数据有 3个,一个是中序的数组,一个是后序的数组,还有一个 是数组的长度; buildtree ( ) 是一个  Node 的指针型的递归函数,返回的是一个节点指针,传入的参数有3个,一个数中序数组的头指针,一个是后序数组的头指针,一个是数组的长度,这个长度可以同时表示第一个数组和第二个数组的长度,因为两个数组长度一定是相同的,数组以指针的形式传入函数只需要写变量名就行了(不用 inO[ ] 这样);然后再看buildtree这个递归函数,这个递归函数其实可以看作是 DFS,如果会用DFS的话,会很好理解;一个树可以没有左子树也可以没有右子树,但是是一定存在根节点的,所以,我们在两个数组中,要找的只是根节点,如果你通过左右节点去找是有可能出错的,因为,这个树有可能没有左右节点,后序数组的根节点,一定在数组的最后一个,确定树的过程就是,后序数组找到根节点,然后通过中序数组去找左右子树,然后从上到下,不断的扩充这颗树,  比如  层次遍历 ( 1 2 3 4 5 6 7) 这个树 它的中序数组是 4 2 5 1 6 3 7, 后序数组是 4 5 2 6 7 3 1 ; 后序数组的最后一个数 1 一定就是根节点, 那么就有  中序(左 4 2 5 )1 ( 右 1 6 3 )   后序 (左 4 5 2)(右 6 7 3)1 ; 那么 1 的左节点是哪个? 这里假设 p 为 中序数组的下标,那么 1 的左节点就是   后序数组【p - 1】,而右节点就是 (假设 len = 中序数组长度 (后序数组长度))后序数组【len - 2】;可以自己多写几个不一样的树,来验证一下,那么有了这个规律就能写出这个递归函数了,每次DFS 左子树数组 和DFS 右子树数组,然后把这个DFS返回的指针 赋给 当前 p->left  和 p-> right; 这里有一个指针的知识就是 假设一个数组 a【N】,那么 dfs(int * a);dfs(a) 传入的就是从a【0】开始的整个数组,如果 dfs(a + 1) 那么传入的就是 从a【1】 开始的 整个数组,同理的,dfs(a + x) 就是 从a【x】  开始的整个数组; 





猜你喜欢

转载自blog.csdn.net/godleaf/article/details/80873761