二叉树重建 及 遍历
题目:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
- 前序序列的第一个就是根节点。
- 然后根据节点值找出根节点在中序遍历序列中的位置,然后前面的就是左子树,后面的就是右子树。
- 同时分割前序遍历序列
- 利用递归的思想,递归地重建左右子树
实现:
下面的实现还有可优化的地方,就是找到根节点所在的序号后,直接生成左右子树的 前序和中序遍历序列。
//对于中序遍历,根节点左边的节点位于二叉树的左边,根节点右边的节点位于二叉树的右边
//利用上述这点,对二叉树节点进行归并
for(int i=0;i<gen;i++)
{
left_in.push_back(in[i]);
left_pre.push_back(pre[i+1]);//前序第一个为根节点
}
for(int i=gen+1;i<inlen;i++)
{
right_in.push_back(in[i]);
right_pre.push_back(pre[i]);
}
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size()==0 || vin.size()==0)
return nullptr;
int rootVal = pre.front();
TreeNode* root = new TreeNode(rootVal);
vector<int> subPreL, subVinL;
vector<int> subPreR, subVinR;
int indexInVin = 0;
while(vin[indexInVin]!=rootVal && indexInVin<vin.size())
indexInVin++;
if(vin[indexInVin]!=rootVal || indexInVin>=vin.size())
return nullptr;
//throw std::exception("Invalid vin arr.");
for(int i=0; i<indexInVin; ++i)
subVinL.push_back(vin[i]);
for(int i=indexInVin+1; i<vin.size(); ++i)
subVinR.push_back(vin[i]);
for(int i=1; i<indexInVin+1; ++i)
subPreL.push_back(pre[i]);
for(int i=indexInVin+1; i<pre.size(); ++i)
subPreR.push_back(pre[i]);
root->left = reConstructBinaryTree(subPreL, subVinL);
root->right = reConstructBinaryTree(subPreR, subVinR);
return root;
}
};
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if (pre.size() != vin.size()) return NULL;
TreeNode* root = new TreeNode(pre[0]);
if(pre.size()==1 && vin.size()==1)
return root;
vector<int> leftVin;
vector<int> rightVin;
bool dirMark = false;
for(int i=0; i<vin.size(); ++i)
{
if(vin[i] == pre[0])
{
dirMark = true;
continue;
}
if(!dirMark)
leftVin.push_back(vin[i]);
else
rightVin.push_back(vin[i]);
}
vector<int> leftPre;
vector<int> rightPre;
for(int i=1; i<pre.size(); ++i)
{
if(i-1<leftVin.size())
leftPre.push_back(pre[i]);
else
rightPre.push_back(pre[i]);
}
if(leftVin.size()>0 && leftPre.size()>0)
{
root->left = reConstructBinaryTree(leftPre, leftVin);
}
if(rightVin.size()>0 && rightPre.size()>0)
{
root->right = reConstructBinaryTree(rightPre, rightVin);
}
return root;
}
};
二叉树的三种遍历方式
https://www.jianshu.com/p/49c8cfd07410
递归形式
//前序遍历, 中序和后序 改核心三句的顺序就行
void preorder(TreeNode *root, vector<int> &path)
{
if(root != NULL)
{
path.push_back(root->val);
preorder(root->left, path);
preorder(root->right, path);
}
}
//更简单的非递归前序遍历
void preorderTraversalNew(TreeNode *root, vector<int> &path)
{
stack< pair<TreeNode *, bool> > s;
s.push(make_pair(root, false));
bool visited;
while(!s.empty())
{
root = s.top().first;
visited = s.top().second;
s.pop();
if(root == NULL)
continue;
if(visited)
{
path.push_back(root->val);
}
else
{
s.push(make_pair(root->right, false));
s.push(make_pair(root->left, false));
s.push(make_pair(root, true));
}
}
}
//倒着看,压入的是栈,先进后出
//前序
s.push(make_pair(root->right, false));
s.push(make_pair(root->left, false));
s.push(make_pair(root, true));
//中序
s.push(make_pair(root->right, false));
s.push(make_pair(root, true));
s.push(make_pair(root->left, false));
//后序
s.push(make_pair(root, true));
s.push(make_pair(root->right, false));
s.push(make_pair(root->left, false));
//简化后的前序
void preorderTraversalNew(TreeNode *root, vector<int> &path)
{
stack<TreeNode *> s;
s.push(root);
while(!s.empty())
{
root = s.top();
s.pop();
if(root == NULL)
{
continue;
}
else
{
path.push_back(root->val);
s.push(root->right);
s.push(root->left);
}
}
}