(第23天)【leetcode题解】二叉树的统一迭代法

94、二叉树的中序遍历

思路

  • 显式的维护一个栈,在栈中按照"右中左"的顺序把节点压入栈中。
  • 没法找到一次性把所有节点按照顺序压入栈中的终止条件。
  • 换一种方法。把节点按顺序压入栈中,同时把要添加进结果集的节点添加标记。
  • 使用标记进行条件判断。遇到标记,表示遇到了要添加进结果集的节点;没有遇到标记时,则继续遍历二叉树,把节点按顺序压入栈中。

代码

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        //访问节点,填充结果集
        while (!st.empty()) {
            TreeNode* node = st.top();//每次取出栈顶元素
            if (node != NULL) {//还没有遇到要填充到结果集里的元素
                st.pop();//将该节点弹出,便于下面把右中左节点压入栈中
                if (node -> right) st.push(node -> right);//右节点
                st.push(node);//中节点
                st.push(NULL);//给中节点添加标记
                if (node -> left) st.push(node -> left);//左节点
            } else {//遇到了要加入结果集的元素
                st.pop();//把标记NULL弹出
                node = st.top();//从栈中取出要加入结果集的元素
                st.pop();
                res.push_back(node -> val);//加入到结果集
            }
        }
        return res;
    }
};

144、二叉树的前序遍历

思路

  • 对比中序遍历,只是修改了把节点压入栈的顺序
  • 仍然需要给要加入结果集的元素添加标记

代码

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> res;
        if (root != NULL) st.push(root);

        while (!st.empty()) {
            TreeNode* node = st.top();//每次都要获取栈顶元素
            if (node != NULL) {//没遇到要填充进结果集的元素
                st.pop();//弹出当前元素,之后按顺序压入节点
                if (node -> right) st.push(node -> right);//右
                if (node -> left) st.push(node -> left);//左
                st.push(node);//中
                st.push(NULL);//进行标记
            } else {//遇到要填充进结果集的元素
                st.pop();//弹出标记
                node = st.top();//获取目标元素
                st.pop();
                res.push_back(node -> val);//加入结果集
            }
        }
        return res;
    }
};

145、二叉树的后序遍历

思路

  • 相比于中序遍历,也只是改变里把节点压入栈的顺序。
  • 压入栈的顺序不同也是因为三种遍历方式不同。

代码

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> res;
        if (root != NULL) st.push(root);

        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                st.push(node);//中
                st.push(NULL);//标记
                if (node -> right) st.push(node -> right);//右
                if (node -> left) st.push(node -> left);//左
            } else {
                st.pop();//弹出标记
                node = st.top();
                st.pop();
                res.push_back(node -> val);
            }
        }
        return res;
    }
};

思考

  1. 在每轮遍历中,要给哪个节点添加标记?
  • 给节点添加标记的目的是确定下来这个节点在加入结果集时的顺序。
  • 经过模拟得出,每轮遍历应该给中间节点添加标记,来确定正确X序遍历的顺序。
  • 因为三种遍历顺序的不同,将节点压入栈中的顺序也不同,受到标记的中间节点不一定会在被标记之后紧接着被添加进结果集,而是先被确定了加入结果集的顺序。
  1. 添加标记的作用
  • 将栈中的节点加入结果集的顺序确定下来。
  • 利用标记可以进行条件判断,从而可以把被标记的节点添加进结果集。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值