递归建树,先序中第一个字符是树根,随后在中序中找到位置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;
}

京公网安备 11010502036488号