二叉树遍历非递归写法: 栈

文章目录

  • [1. 前序遍历](#1. 前序遍历)
  • [2. 中序遍历](#2. 中序遍历)
  • [3. 后序遍历](#3. 后序遍历)

1. 前序遍历

前序遍历,顺序为根左右 ,因此在借助栈 的非递归实现中,可以立即访问,因此前序遍历的非递归写法是较为简单的。需要注意的是,栈先进后出的顺序,因此左子树,右子树的访问顺序,入栈时,应先入右子树,再入左子树。
LEETCODE 链接

cpp 复制代码
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        using node = TreeNode;
        stack<node*> st;
        vector<int> ret;
        if(root)
            st.push(root);
        while(st.size()) {
            node* cur = st.top();
            st.pop();
            ret.push_back(cur->val);
            if(cur->right)
                st.push(cur->right);
            if(cur->left)
                st.push(cur->left);
        }
        return ret;
    }
};

2. 中序遍历

中序遍历顺序为左根右 ,因此当前结点不能立刻记录访问 ,而应该确保左子树穷尽后,再记录该结点,然后再对该结点的右子树进行中序遍历 。中序遍历非递归写法,相较于前序遍历,略微复杂,因为要先记录访问左子树后,方能记录当前结点。
LEETCODE 链接

cpp 复制代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while(st.size() || cur) {
            while(cur) {
                st.push(cur);
                cur = cur->left;
            }
            TreeNode* node = st.top();
            st.pop();
            ret.push_back(node->val);
            cur = node->right;
        }
        return ret;
    }
};

3. 后序遍历

后序遍历的顺序为左右根 ,后序遍历是最为复杂的,因为当前结点的访问,必须在当前结点的左子树和右子树都访问后,才能访问记录。

下面,介绍一种巧妙直观的迭代写法 。后序遍历顺序为左右根 ,将遍历访问结果反转,即为根右左 ,实质近似于前序遍历的根左右 ,即迭代写法一致,仅需调整左右子树根结点入栈顺序即可 ,最后将得到的结果做反转 ,即为最终结果。
LEETCODE 链接

cpp 复制代码
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        using node = TreeNode;
        vector<int> ret;
        stack<node*> st;
        if(root)
            st.push(root);
        while(st.size()) {
            node* cur = st.top();
            st.pop();
            ret.push_back(cur->val);
            if(cur->left)
                st.push(cur->left);
            if(cur->right)
                st.push(cur->right);
        }    
        ranges::reverse(ret);
        return ret;
    }
};
相关推荐
sm_926787056 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
by209996 小时前
C++ 多态:同一个基类接口,调用不同的函数
开发语言·c++·经验分享·多态
colinu7 小时前
C++ 异步任务与线程生命周期:`std::async`、`future`、`thread`、`jthread` 与协作式退出
java·jvm·c++
wuminyu7 小时前
ForkJoinPool窃取线程在扫描其他WorkQueue时的随机采样算法与Phase线程挂起唤醒机制解析
java·linux·c语言·jvm·c++
longlongzihan7 小时前
链表找环:Floyd 判圈算法(LeetCode 141 & 142 )
c++·算法·leetcode·链表
liulilittle8 小时前
Linux 下 select 测试函数
linux·服务器·网络·数据库·c++·select·c
无忧.芙桃8 小时前
C++语言原理与实践(十二):list类的底层实现
c++·windows·list
沫璃染墨8 小时前
《Linux工程实践篇(二):线程池实战——从线程安全单例到完整源码实现》
linux·开发语言·c++·单例模式·设计模式·系统架构
有只小白叫岳飒9 小时前
c++智能指针 unique_ptr与函数调用
c++
Leo.yuan9 小时前
Kafka+Flink拼凑,还是FineDataLink 5.0一体化?实时数据处理的两种思路
c++·mfc