二叉树遍历(非递归解法)一个模板解决三种遍历

二叉树遍历(非递归解法)

方法

看了leetcode上 PualKing的秒杀全场吧,后浪的解法。用同一个模板解决了三种递归。主要先理解了一个解法,剩下两个就是调换了一下压栈的顺序。
写一下自己看的时候理解的点:

  1. 首先看的时候要分清push()、pop()和push_back(),要不然就不知道每一步是再做什么。
  2. 关于为什么要添加空结点:这个对我来说却是还有点不太好理解。具体带个二叉树进去可能会比较好理解。
    作者的这个思想本质上还是压栈问题。也就是怎么区分要弹出的结点和要压栈的结点。
    以前序遍历为例:
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;  //保存结果
        stack<TreeNode*> call;  //调用栈
        if(root!=nullptr) call.push(root);  //首先介入root节点
        while(!call.empty()){
            TreeNode *t = call.top();
            call.pop();  //访问过的节点弹出
            if(t!=nullptr){
                if(t->right) call.push(t->right);  //右节点先压栈,最后处理
                if(t->left) call.push(t->left);
                call.push(t);  //当前节点重新压栈(留着以后处理),因为先序遍历所以最后压栈
                call.push(nullptr);  //在当前节点之前加入一个空节点表示已经访问过了
            }else{  //空节点表示之前已经访问过了,现在需要处理除了递归之外的内容
                res.push_back(call.top()->val);  //call.top()是nullptr之前压栈的一个节点,也就是上面call.push(t)中的那个t
                call.pop();  //处理完了,第二次弹出节点(彻底从栈中移除)
            }
        }
        return res;
    }
};

如果当前t指向的结点不为空,那么就需要将它的左右子树进行压栈。反之,则可以直接输出空结点下面的结点。这应该就是空结点的一个作用,用以区分压栈操作和输出操作。
再者就是空结点要在t之后添加,否则会超时。

  1. res.push_back(call.top()->val);这条语句也要注意

代码

同上。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> call;
        if(root!=nullptr) call.push(root);
        while(!call.empty()){
            TreeNode *t = call.top();
            call.pop();
            if(t!=nullptr){
                if(t->right) call.push(t->right);
                call.push(t);  //在左节点之前重新插入该节点,以便在左节点之后处理(访问值)
                call.push(nullptr); //nullptr跟随t插入,标识已经访问过,还没有被处理
                if(t->left) call.push(t->left);
            }else{
                res.push_back(call.top()->val);
                call.pop();
            }
        }
        return res;
    }
};

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> call;
        if(root!=nullptr) call.push(root);
        while(!call.empty()){
            TreeNode *t = call.top();
            call.pop();
            if(t!=nullptr){
                call.push(t);  //在右节点之前重新插入该节点,以便在最后处理(访问值)
                call.push(nullptr); //nullptr跟随t插入,标识已经访问过,还没有被处理
                if(t->right) call.push(t->right);
                if(t->left) call.push(t->left);
            }else{
                res.push_back(call.top()->val);
                call.pop();
            }
        }
        return res;   
    }
};
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页