标签:
参考:《剑指offer》纪念版
情况1.:给出树的前序序列和中序序列,输出后序序列
情况2 :给出树的后序序列和中序序列,输出前序序列
解决方法:根据所给出的两个序列,构造出(重建)二叉树,然后按要求再遍历输出。
重建二叉树主要利用了递归的思想,最重要的是找出序列的范围(函数传参),这个要非常仔细,很容易出错。一定要在纸上画出图,然后根据图来确定范围。
用到的两个函数:
以情况1为例:
主要用到了两个函数:
BinaryTreeNode* Construct(char* preorder, char* inorder, int length)//给出前序序列,中序序列,长度,重建二叉树
BinaryTreeNode* ConstructCore ( char* startPreorder, char* endPreorder, char* startInorder, char* endInorder )//前序序列起始位置,中序序列起始位置
完整的代码:
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <set> #include <map> #include <stack> #include <queue> using namespace std; struct BinaryTreeNode { char m_nValue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight; }; bool invalidInput;//输入的序列是否合法 void Visit(BinaryTreeNode* node)//访问节点 { cout << node->m_nValue; } void PreorderTraverse(BinaryTreeNode* root)//前序遍历 { if(root == NULL) return; Visit(root); PreorderTraverse(root->m_pLeft); PreorderTraverse(root->m_pRight); } void InorderTraverse(BinaryTreeNode* root)//中序遍历 { if(root == NULL) return; InorderTraverse(root->m_pLeft); Visit(root); InorderTraverse(root->m_pRight); } void PostorderTraverse(BinaryTreeNode* root)//后序遍历 { if(root == NULL) return; PostorderTraverse(root->m_pLeft); PostorderTraverse(root->m_pRight); Visit(root); } BinaryTreeNode* ConstructCore ( char* startPreorder, char* endPreorder, char* startInorder, char* endInorder )//前序序列起始位置,中序序列起始位置 { BinaryTreeNode* root = (BinaryTreeNode* )malloc(sizeof(BinaryTreeNode)); char rootValue = startPreorder[0];//根节点的值为前序遍历序列的第一个值 root->m_nValue = rootValue; root->m_pLeft = root->m_pRight = NULL; if(startPreorder == endPreorder) { if(startInorder == endInorder && *startPreorder == *startInorder)//如果前序序列和中序序列都只有一个字母,且二者字母相同 return root; else { invalidInput = true; return NULL; } } //在中序序列中找到根节点的位置 char* rootInorder = startInorder;//根节点在在中序序列中的位置 while(rootInorder <= endInorder && (*rootInorder) != rootValue) ++ rootInorder; if(rootInorder > endInorder)//找不到根节点 { invalidInput = true; return NULL; } char leftLength = rootInorder - startInorder;//左子树的长度 char* leftPreorderEnd = startPreorder + leftLength;//左子树在前序序列中的终点位置 if(leftLength > 0)//构造左子树 { root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1); } char rightLength = endPreorder - startPreorder - leftLength; if(rightLength > 0)//构造右子树 { root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder); } return root; } BinaryTreeNode* Construct(char* preorder, char* inorder, int length)//给出前序序列,中序序列,长度,重建二叉树 { if(preorder == NULL || inorder == NULL || length < 0) return NULL; return ConstructCore(preorder, preorder + length -1, inorder, inorder + length -1); } char preOrder[50], inOrder[50]; int main() { while(cin>> preOrder >> inOrder) { invalidInput = false; int len = strlen(preOrder); BinaryTreeNode* root = Construct(preOrder, inOrder, len); if(invalidInput == true) { cout <<"Invalid input." <<endl; continue; } cout << "前序遍历为: " ; PreorderTraverse(root); cout << endl; cout << "中序遍历为: " ; InorderTraverse(root); cout << endl; cout << "后序遍历为: " ; PostorderTraverse(root); cout << endl; } return 0; }
情况2和情况1很类似,也是利用递归,重要的也是找准序列的范围,下面给出关键代码:
BinaryTreeNode* ConstructCore2 ( char* startPostorder, char* endPostorder, char* startInorder, char* endInorder )//后序序列起始位置,终点位置, 中序序列起始位置,终点位置 { BinaryTreeNode* root = (BinaryTreeNode*) malloc(sizeof(BinaryTreeNode)); root->m_nValue = (*endPostorder);//根节点为后序序列的最后一个值 root->m_pLeft = root->m_pRight = NULL; int rootValue = root->m_nValue; if(startPostorder == endPostorder) { if(startInorder == endInorder && *startPostorder == *startInorder)//如果后序序列和中序序列都只有一个节点,且节点值相等 return root; else { invalidInput = true; return NULL; } } //在中序序列中找到根节点的位置 char* rootInorder = startInorder; while(rootInorder <= endInorder && *rootInorder != rootValue) ++ rootInorder; if(rootInorder > endInorder)//没找到 { invalidInput = true; return NULL; } //构造左子树 int leftLength = rootInorder - startInorder; if(leftLength > 0) { root->m_pLeft = ConstructCore2(startPostorder, startPostorder + leftLength - 1, startInorder, rootInorder - 1);//这种参数看着图写 } int rightLength = endInorder - startInorder - leftLength; if(rightLength > 0) { root->m_pRight = ConstructCore2(endPostorder - rightLength, endPostorder - 1, rootInorder + 1, endInorder); } return root; } BinaryTreeNode* Construct2(char* postorder,char* inorder, int length)//给出后序序列,中序序列,长度,重建二叉树 { if(postorder == NULL || inorder == NULL || length < 0) return NULL; return ConstructCore2(postorder, postorder + length -1, inorder, inorder + length - 1); }
int* rootInorder = startInorder; while(rootInorder <= endInorder && *rootInorder != rootValue) ++rootInorder; if(rootInorder == endInorder && *rootInorder != rootValue) throw std::exception("Invalid input.");感觉有问题。 下面为什么还要判断 rootInorder == endInorder ?
[剑指offer] 重建二叉树,根据前中,输出后,根据中后,输出前
标签:
原文地址:http://blog.csdn.net/sr_19930829/article/details/50801063