递归建树,先序中第一个字符是树根,随后在中序中找到位置pos,preorder中从1长度为pos的是左子树,inorder从0开始长度为pos的就是左子树长度;类似地,preorder从pos+1一直到末尾是右子树长度,inorder从pos+1到末尾是右子树先序;

尤其注意return与=指针赋值的作用,当不断分割直到字符串为空是时,此时return NULL,返回时正好赋值给外面的newnode->left或newnode->right,这样就正确初始化了叶子结点,同时,结点左右孩子建立好后在最后返回pNewNode也正好通过指针赋值初始化为了父节点的左右孩子,一棵树从叶结点到根结点慢慢建立起来

下面是一个简单的递归运行的例子,preorder是ABC,inorder是BAC

#include <cstdio>
#include <string>
using namespace std;

struct TreeNode {
    char data;
    TreeNode* lchild, *rchild;
};

// rebuild的返回值表示子树根结点的地址
TreeNode* rebuild(string preOrder, string inOrder) {
    if (preOrder.size() == 0) {
        return NULL; // 插入叶子结点
    }
    else { // 插入非叶子,需要申请空间并递归建立它的左右子树
        // 先序序列中第一个字符就是根
        char rootdata = preOrder[0];
        // 为树根创建新结点
        TreeNode* pNewNode = new TreeNode;
        pNewNode->data = rootdata;
        // 拿到树根在中序序列中的下标,正好也是左子树的长度
        int pos = inOrder.find(rootdata);
        // 再返回到先序中,在同样长度的子串中再确定子树根结点,再到中序序列中去分割,如此循环往复,直到只有一个结点
        pNewNode->lchild = rebuild(preOrder.substr(1, pos), inOrder.substr(0, pos));
        pNewNode->rchild = rebuild(preOrder.substr(pos + 1), inOrder.substr(pos + 1));
        // 返回整棵树的根,其他递归函数中没有修改,仅在本函数中有效
        return pNewNode; // 返回子树的根,最后返回整棵树的根
    }
}

void postOrder(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    postOrder(root->lchild);
    postOrder(root->rchild);
    printf("%c", root->data);
}

// 根据先序遍历与中序遍历重建树并输出后序遍历序列
int main() {
    char preOrder[20], inOrder[30];
    while (scanf("%s%s", preOrder, inOrder) != EOF) {
        TreeNode* root = rebuild(preOrder, inOrder);
        postOrder(root);
        printf("\n");
    }
    return 0;
}