开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
二叉树的前序遍历
前序遍历的顺序:根-> 左子树->右子树 因为递归可以回退到上一层也就是根,所以非递归就要储存每一次遍历的节点,用于回退时就行遍历,储存的这个结构用栈。 我们从根节点开始遍历,遍历的时候把节点保留在栈中,同时把节点的值也进行访问,根访问完就是左树,而左树也可以是按照这个逻辑走的,所以我们一直是访问根,访问左树;什么时候打破这个局面呢?当该节点为空的时候,说明子树访问完成,该访问右子树了;而右子树的访问方式也是按照上述的方式进行访问的。怎么访问右树呢?——我们之前栈顶就保存了根节点,我们只需要取出栈顶节点,然后访问右树,同时删除栈顶节点。遍历完成的标志为栈为空或者是该节点为空。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ret;
stack<TreeNode*> st;
if(root==nullptr)
return ret;
TreeNode* cur=root;
while(cur||!st.empty())
{
while(cur)
{
st.push(cur);
ret.push_back(cur->val);
cur=cur->left;
}
cur=st.top()->right;
st.pop();
}
return ret;
}
};
二叉树的中序遍历
中序遍历的顺序:左子树->根-> 右子树 还是用栈保存根节点,第一个遍历的是根,但是此节点我们不能访问,我们要继续访问左子树,什么时候停止进行访问呢?访问到空,这时候该访问根节点了,而根节点就保存在栈中,下面就是访问右树,而右树的访问和上述的访问是一样的。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ret;
if(root==nullptr)
return ret;
stack<TreeNode*> st;
TreeNode* cur=root;
while(cur||!st.empty())
{
while(cur)
{
st.push(cur);
cur=cur->left;
}
ret.push_back(st.top()->val);
cur=st.top()->right;
st.pop();
}
return ret;
}
};
二叉树的后序遍历
后序遍历的顺序: 左子树->右子树->根 我们栈里面还是存的根节点,当我们遍历到空的时候,说明左子树遍历完成,要不要访问根呢?要看右子树,当右子树为空的时候,就可以访问该节点,如果不为空,要继续按上面的方式继续访问。 当左右子树都访问完的时候,就是访问根节点了,此时的根节点是需要访问的,但是我们怎么知道此节点能不能访问是个问题,所以我们要有一个指针指向上一个访问的节点,当该节点的右节点等于该节点的上一个节点的时候,说明该节点已经访问访问完成左右节点了,可以访问该根节点了。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> ret;
if(root==nullptr)
return ret;
stack<TreeNode*> st;
TreeNode* cur=root;
TreeNode* pre=nullptr;
while(cur||!st.empty())
{
while(cur)
{
st.push(cur);
cur=cur->left;
}
TreeNode* top=st.top();
if(top->right==nullptr||top->right==pre)
{
ret.push_back(st.top()->val);
pre=st.top();
st.pop();
}
else
cur=st.top()->right;
}
return ret;
}
};