二叉树的前,中,后序的非递归实现(c++)

前言

对于二叉树来说,遍历它有多种方式,其中递归遍历是比较简单的,但是非递归的实现就有一定的难度,在这里介绍一种非递归实现二叉树遍历的方式。

1.前序遍历

1.1思路

其实对于二叉树的非递归实现,实际上就是用代码来模拟操作系统压栈和弹栈的过程 。让我们一起来看看吧,首先将一棵树 分为左边节点和左边节点的右子树。如图:

然后借助于一个栈,先将左边节点入栈,入栈时要将节点的值存到数组中。将左边节点全部入栈后,再来将左边节点的右子树入栈,重复上述过程。直至栈为空并且,当前的指针也为空,此时完成二叉树的前序遍历。如图:

1.2代码实现

cpp 复制代码
    vector<int> preorderTraversal(TreeNode* root)
    {
        vector<int> v;
        stack<TreeNode*> sT;
        //1.处理左边节点
        //2.处理左边节点的右子树
        TreeNode * cur = root;
        while(cur ||  !sT.empty()  )
        {
            while(cur)
            {
                //左边节点入栈
                sT.push(cur);
                v.push_back(cur->val);
                
                cur = cur -> left;
            }
            TreeNode* p = sT.top();
            sT.pop();
            cur = p -> right;
            //左边节点的右子树入栈
        }
        return v;
    }

2.中序遍历

2.1思路

中序遍历的思路和前序遍历基本相同,就是此时左边节点入栈时不会将左边节点的val插到数组中,而是在栈中将节点的指针取出时再尾插到数组中。

2.2代码实现

cpp 复制代码
  vector<int> inorderTraversal(TreeNode* root) 
    {
        vector<int> ret;
        stack< TreeNode* > sT;
        TreeNode* cur = root;
        while(cur || !sT.empty())
        {
            //树的左边节点入栈
            while(cur)
            {
                sT.push(cur);
                cur = cur -> left;
            }
            //取出栈顶节点的指针
            //将栈顶节点指针的val尾插到数组中
            TreeNode * top = sT.top();
            sT.pop();
            //左边节点的右子树入栈
            cur = top -> right;
            ret.push_back(top->val);
        }
        return ret;
    }

3.后序遍历

3.1思路

后序遍历沿用了中序遍历的思路,唯一不同的是将左边节点依次入栈后,出栈时先处理当前节点的左子树,然后将右子树入栈,等处理完右子树后再来处理当前节点。

3.2代码实现

cpp 复制代码
    vector<int> postorderTraversal(TreeNode* root) 
    {
        TreeNode * cur = root;
        TreeNode * back = nullptr;//用来记录处理上一个节点
        vector<int> ret;
        stack<TreeNode*> sT;
        while(cur || !sT.empty() )
        {
            //左边节点入栈
            while(cur)
            {
                sT.push(cur);
                cur = cur->left;
            }
            //取出栈顶数据
            TreeNode* top = sT.top();
            
            if(top->right == nullptr || top->right == back)
            {
                ret.push_back(top->val);
                back = top;//记录处理过的节点
                sT.pop();
            }
            else
            {
                //左边节点的右子树入栈
                cur = top -> right;
            }
        }
        return ret;
    }

后续遍历需要注意的是在什么时候来对当前节点进行处理 ,要先处理左右节点之后对当前节点进行处理,如果右节点为空很好办直接判断右节点为不为空就可以了,但是如果右节点不为空呢?怎么确保右节点已经处理过了再来对当前节点进行处理呢,这里提供一种较为简单的思路,通过一个指针来记录上次处理的节点,因为后序遍历总是按照左子树,右子树和根的处理顺序来的所以我们只需要处理比较上一个处理的节点是不是当前节点的右子树就可以知道 当前节点的右子树是否已经被处理过了,来判断当前节点是否需要处理。

讲的不好,希望不要喷我。

相关推荐
Alpha first13 小时前
C++核心知识点梳理:类型兼容、多继承与虚基类
开发语言·c++
.小小陈.13 小时前
C++初阶9:list使用攻略
开发语言·c++·学习·list
qq_5895681013 小时前
@NotBlank与@NotEmpty注解无法导入
java·开发语言
天赐学c语言13 小时前
12.14 - 搜索旋转排序数组 && 判断两个结构体是否相等
数据结构·c++·算法·leecode
1024肥宅13 小时前
JavaScript 性能与优化:数据结构和算法
前端·数据结构·算法
超自然祈祷14 小时前
水声相关公式C++实现
开发语言·c++
仰泳的熊猫14 小时前
1112 Stucked Keyboard
数据结构·c++·算法·pat考试
淼淼76314 小时前
QT表格与数据
开发语言·qt
smile_Iris14 小时前
Day 38 GPU训练及类的call方法
开发语言·python
三月微暖寻春笋14 小时前
【和春笋一起学C++】(五十一)复制构造函数
c++·复制构造函数·显式复制构造函数·隐式复制构造函数