LeetCode网站上的题目
https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
1.递归方法
//递归
class Solution
{
private:
map<int,int>index;
//函数意义:给定树在前序遍历和中序遍历时,所有节点的坐标区间,建立这棵树
TreeNode* Creat_Tree_By_Pre_And_In(vector<int>&preorder,vector<int>inorder,int pre_left,int pre_right,int in_left,int in_right)
{
if(pre_left>pre_right)//递归终止条件,不使用=的原因是在树节点数为1的时候,也要建立节点
return nullptr;
//前序遍历的第一个节点就是根节点
int root_pre_index=pre_left;
//寻找根节点在中序遍历中的位置
int root_in_index=index[preorder[root_pre_index]];
//建立当前根节点
TreeNode*root=new TreeNode(preorder[root_pre_index]);
//计算当前根节点的左子树的节点数目
int Left_Tree_Node_Nums=root_in_index-in_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 Left_Tree_Node_Nums」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root->left=Creat_Tree_By_Pre_And_In(preorder,inorder,pre_left+1,pre_left+Left_Tree_Node_Nums,in_left,root_in_index-1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root->right=Creat_Tree_By_Pre_And_In(preorder,inorder,pre_left+Left_Tree_Node_Nums+1,pre_right,root_in_index+1,in_right);
return root;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
int i;
int Tree_Nodes_Nums=inorder.size();
for(i=0;i<Tree_Nodes_Nums;i++)
index[inorder[i]]=i;
return Creat_Tree_By_Pre_And_In(preorder,inorder,0,Tree_Nodes_Nums-1,0,Tree_Nodes_Nums-1);
}
};
2.迭代方法
//迭代
/*1.我们用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(前序遍历的第一个节点),指针指向中序遍历的第一个节点;
2.我们依次枚举前序遍历中除了第一个节点以外的每个节点。如果 index 恰好指向栈顶节点,那么我们不断地弹出栈顶节点并向右移动 index,并将当前节点作为最后一个弹出的节点的右儿子;如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的左儿子;
3.无论是哪一种情况,我们最后都将当前的节点入栈。(因为所有节点都有可能是子树根节点)*/
class Solution
{
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
if (!preorder.size())
{
return nullptr;
}
TreeNode* root = new TreeNode(preorder[0]);//前序遍历的第一个就是树的根节点
stack<TreeNode*> stk;
stk.push(root);
int inorderIndex = 0;//中序遍历数组的下标
for (int i = 1; i < preorder.size(); ++i)
{
//顺序就是在前序遍历数组中遍历到当前节点时,以当前节点的前一个节点(即栈顶节点为根节点来进行树的建立)
int preorderVal = preorder[i];//当前前序遍历的遍历值
TreeNode* node = stk.top();//根节点
if (node->val != inorder[inorderIndex])
//这条语句就是在建立当前根节点的左节点
{
node->left = new TreeNode(preorderVal);
stk.push(node->left);
}
//前序遍历构造的数组顺序是 根节点 左子树 右子树
//中序遍历构造的数组顺序是 左子树 根节点 右子树
//所以前序遍历的数组的最后一个元素比不可能是某个子树的根节点
//else判断的就是当前序数组的值与中序数组的相同时,说明当前前序数组遍历根节点(即栈顶元素节点)没有左子树了
//那么当前的数组遍历值就是入栈的那些左节点中的某一个的右节点
//前序遍历与中序遍历在遇到一个右节点之前顺序是相反的,所以就不断弹出栈中元素,同时移动中序数组中的指针,
//直到栈为空或者栈顶元素和中序数组指针指向的元素不相等了,说明上一个弹出的节点的右节点就是当前前序遍历的遍历值
//再把当前前序遍历的遍历值入栈,可作为子树根节点
else
{
while (!stk.empty() && stk.top()->val == inorder[inorderIndex])
{
node = stk.top();
stk.pop();
++inorderIndex;
}
node->right = new TreeNode(preorderVal);
stk.push(node->right);
}
}
return root;
}
};