俗话说的好“你先前跳过的坑,迟早都要再踩进去的”
昨天考的PAT的利用二叉树的前序和中序遍历得到后序遍历的第一个值。想起在leetcode上做过,却没做出来。特此,对二叉树的三种遍历做个复习。
二叉树的三种遍历分别为:前序遍历(preorder),中序遍历(inorder),后序遍历(postorder),这三种遍历的区别直接体现在代码上,看如下三个代码:
void preorder(TreeNode* root)
{
printNode(root);
preorder(root->left);
preorder(root->right);
}
void inorder(TreeNode* root)
{
inorder(root->left);
printNode(root);
inorder(root->right);
}
void postorder(TreeNode* root)
{
postorder(root->left);
postorder(root->right);
printNode(root);
}
以上就是三种遍历方式的代码,代码就是纯递归。只是输出的不同。那么,再来看下面的实例:
那么前序遍历(preorder)为:ABDCEGFHI
中序遍历(inorder)为:BDAGECHFI
后序遍历(postorder)为:DBGEHIFCA
大家可以根据上面的代码,自己推断一下遍历的结果。
从这些遍历的结果可以看到以下几个特点:
1.遍历的优先级左边优先.
2.前序遍历不断递归左边的点(将遇到的点入栈).
3.递归到底了,返回上面一层到右边(出栈),发生转变的时候,前序遍历的值会刚好等于中序遍历的值.
4.后序遍历刚刚看起来好像没什么规律。但是将后序遍历反转一下呢?得到如下的结果:ACFIHEGBD。再观察一下树,没错了,反转之后得到的结果是树的优先向右遍历的结果。但是什么时候判断到底,也就是什么时候判断要转向了呢?我们也照反转的方式,将中序遍历反转,得到结果:IFHCEGADB。哈哈,没错这是当反转的后序等于反转的中序的时候就说明到底了,需要转向了。
知道了上面四点性质,下面这三道题就很简单了:
leetcode105:
利用前序遍历和后序遍历构建树。
根据性质1,2,3
建立一个栈,遍历前序向栈压结点。直到和中序遍历的值相等,说明到底,出栈,转向。
代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.empty() || inorder.empty()) return NULL;
stack<TreeNode*> stree;
int size=inorder.size();
int i=1;
int j=0;
int flag=0; //向右进行的标志
TreeNode* node=new TreeNode(preorder[0]);
TreeNode* root=node;
if(preorder.size()==1) return root;
stree.push(node);
while(i<size)
{
//表示应该转向了
if(!stree.empty() && ((stree.top())->val==inorder[j]))
{
node=stree.top();
stree.pop();
flag=1;
j++;
}
else
{
TreeNode* tmp=new TreeNode(preorder[i]);
i++;
if(flag==0)
{
node->left=tmp;
node=node->left;
stree.push(tmp);
}
else
{
node->right=tmp;
node=node->right;
stree.push(tmp);
flag=0;
}
}
}
return root;
}
};
106.利用后序遍历和中序遍历还原树
根据性质四.将中序遍历和后序遍历的结果反转,将右的优先级调整高于左,和上面一样的思路。
代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.empty()) return NULL;
stack<TreeNode *>st;
reverse(inorder.begin(),inorder.end());
reverse(postorder.begin(),postorder.end());
TreeNode* root=new TreeNode(postorder[0]);
TreeNode* node=root;
st.push(node);
int i=1; int j=0; int flag=0; //0说明向右
int size=postorder.size();
while(i<size)
{
if(!st.empty() && (st.top()->val)==inorder[j])
{
node=st.top();
st.pop();
j++;
flag=1; //1说明转向,转向到左
}
else
{
TreeNode *temp=new TreeNode(postorder[i]);
if(flag==0)
{
node->right=temp;
node=node->right;
}
else
{
flag=0;
node->left=temp;
node=node->left;
}
st.push(temp);
i++;
}
}
return root;
}
};
PAT 1138.给出前序和中序遍历,给出后序的第一个值。这个,不多说了
代码:
#include<cstdio>
#include<string>
#include<stack>
#include<iostream>
using namespace std;
struct TreeNode{
int value;
TreeNode* left;
TreeNode* right;
TreeNode(int x):value(x),left(NULL),right(NULL) {}
};
int a[50001];
int b[50001];
int flag3=0;
void postorder(TreeNode* a);
int main()
{
int n;
cin>>n;
for(int i=0;i<n;++i)
{
cin>>a[i];
}
for(int i=0;i<n;++i)
{
cin>>b[i];
}
if(n==1)
{
cout<<a[0];
}
int flag=0;
int i=1;
int j=0;
stack<TreeNode *>st;
TreeNode* root=new TreeNode(a[0]);
TreeNode* node=root;
st.push(root);
while(i<n)
{
//转向
if(!st.empty() && (st.top())->value==b[j])
{
node=st.top();
st.pop();
flag=1;
j++;
}
else
{
TreeNode* tmp=new TreeNode(a[i]);
i++;
if(flag==0)
{
node->left=tmp;
node=node->left;
st.push(node);
}
else
{
node->right=tmp;
node=node->right;
st.push(node);
flag=0;
}
}
}
postorder(root);
}
void postorder(TreeNode* a)
{
if(flag3==1 || a==NULL)
{
return;
}
else
{
postorder(a->left);
postorder(a->right);
if(flag3==0)
{
cout<<(a->value);
flag3=1;
}
}
}