我们知道二叉树的遍历用递归来实现比较简单,代码就几行,如下
void prevorder(Node*root) //前序遍历
{
if(root==nullptr)
return ;
cout<<root->val<<" ";
prevorder(root->left);
prevorder(root->right);
}
void inorder(Node*root) // 中序遍历
{
if(root==nullptr)
return ;
inorder(root->left);
cout<<root->val<<" ";
inorder(root->right);
}
void postorder(Node*root) //后序遍历
{
if(root==nullptr)
return ;
postorder(root->left);
postorder(root->right);
cout<<root->val<<" ";
}
如果不用递归的方式如何做到遍历整棵数呢?
拿到一个节点后要查询它存储的值,还要去它的左右子树做同样的操作,可以用栈来存储一个个的节点地址,先分析前序遍历,传入一个节点,先打印它的值,然后把它入栈,再去它的左子树,遍历,一直到左为空,去栈顶节点,拿到它的右子树,对右子树进行同样的操作,直到栈为空当前节点也为空,就遍历完了整棵树。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*>st;
vector<int>v;
if(root==NULL)
return v;
TreeNode*cur=root;
while(cur||!st.empty()) //当节点为空,栈中也没有节点时遍历完成
{
while(cur) //拿到一个节点非空,先取它的值,再去左子树
{
v.push_back(cur->val);
st.push(cur); //压栈,后面来遍历它的右子树
cur=cur->left;
}
cur=st.top();
st.pop();
cur=cur->right;
}
return v;
}
};
中序遍历就是取到一个节点不为空,就压栈,去它的左子树,直到左为空,拿到栈顶节点,这时查看节点存取的值,然后去它的右子树,结束条件也是栈为空且当前节点为空。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*>st;
vector<int>v;
TreeNode*cur=root;
while(cur||!st.empty())
{
while(cur)
{
st.push(cur); //中序遍历,拿到一个节点,先压栈去遍历它的左子树
cur=cur->left;
}
cur=st.top(); //左子树遍历完再取到节点的值,然后去右子树遍历
st.pop();
v.push_back(cur->val);
cur=cur->right;
}
return v;
}
};
后序遍历就要注意当左子树走完了,回到上一个节点,要判断它的右子树有没有遍历,只有右边也遍历了才取当前节点的值。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*>st;
vector<int>v;
TreeNode*cur=root,*prev=nullptr; //设置一个前节点来区分遍历完左边后,是否也遍历完右边,只有左右都遍历完才去当前节点
while(cur||!st.empty())
{
while(cur)
{
st.push(cur);
cur=cur->left;
}
TreeNode*top=st.top();//取栈顶节点
if(top->right==nullptr||prev==top->right) //右为空或者右边遍历完就取当前节点值
{
v.push_back(top->val);
prev=top; //这里遍历完更新前一个节点
st.pop(); //去上一层
}
else
{
cur=top->right; //这里就说明遍历完左边,右边还没遍历,所以去右边
}
}
return v;
}
};