用非递归实现二叉树的前序中序后序遍历


前言

二叉树的遍历是指按某条搜索路径访问树中的每个结点,使得每个结点均被访问一次,而且仅能访问一次(说明不可二次访问,一遍而过)。遍历一颗二叉树便要决定对根结点N、左子树L和右子树的访问顺序。 二叉树常的的遍历方法有前序遍历(NLR)、中序遍历(LNR)和后序遍历(LRN)三种遍历算法,其中 “序” 指的是根结点在何时被访问。三种遍历方法有递归和非递归两个版本。在本文中主要用非递归的方式去实现二叉树的非递归遍历。

一、了解二叉树的存储结构

在这里插入图片描述

typedef int BTDataType;;  // 数据类型
 
/*二叉树的链式存储结构*/
typedef struct BinaryTreeNode
{
	BTDataType _data; // 数据域
    struct BinaryTreeNode* _left;
    struct BinaryTreeNode* _right; // 左右孩子指针
}BTNode;

二、前序遍历(Preorder Traversal 亦称先序遍历)

访问根结点的操作发生在遍历其左右子树之前

前序遍历整体图解
在这里插入图片描述
首先从根的左子树开始遍历,一直向左遍历,每次遍历时入栈,当所遍历节点左子树不为nullptr时继续向左遍历,直到所遍历左子树的左节点指向nullptr时停止;
在这里插入图片描述
这时入栈的情况和遍历顺序如图所示
在这里插入图片描述
这时D出栈,因为D的左子树为nullptr,不继续向左遍历,故遍历D的右子树,但D的右子树也为nullptr,故不遍历,D本身已经遍历完了。这时,B出栈,遍历B的右子树。
在这里插入图片描述
因为B的右子树不为nullptr,故开始遍历B的右子树,遍历E,E入栈,因为E的左子树不为nullptr,遍历E的左子树。遍历G,G入栈。
在这里插入图片描述
因为G的左子树为nullptr,这时G出栈,遍历G的右子树,但G的右子树也为nullptr.故E出栈,遍历E的右子树,因为E的右子树,因为E的右子树也为nullptr,A出栈,遍历A的右子树,因为A的右子树不为空,开始遍历A的右子树。
在这里插入图片描述
遍历A的右子树,遍历C,C进栈,遍历C的左子树,因为C的左子树为nullptr故C出栈,遍历C的右子树
在这里插入图片描述
遍历F,F进栈,因为F的左右子树都为nullptr,F出战,栈里没有元素。栈为nullptr,遍历结束。
在这里插入图片描述
则遍历顺序为:
在这里插入图片描述
如何利用非递归的方法去进行二叉树的前序遍历呢?
前序遍历记住:节点入栈遍历左子树,出栈遍历右子树
算法思想
**1.开始访问一棵树根节点
2.向左路节点遍历,直到左路节点为空。
3.栈内节点开始出栈,出栈访问它的右子树。
4.栈为空,节点全部入栈出栈遍历了一次,结束遍历。

算法实现

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur=root;
        while(cur||!st.empty())
        {
           //开始访问一颗树
           //1.左路节点
            while(cur)
            {
                v.push_back(top->val);
                st.push(cur);
                cur=cur->left;
            }
            //左路节点的右子树需要访问
            TreeNode*top=st.top();
            st.pop();
            cur=top->right;
        }
        return v;

    }
};

三、中序遍历(Inorder Traversal)

——访问根结点的操作发生在遍历其左右子树之中(间)

中序遍历整体图解
在这里插入图片描述
同样遍历这颗二叉树,先遍历左路节点,中序遍历与前序遍历最大的区别是,**前序遍历,先遍历再入栈,而中序遍历,则是先入栈,出栈时再进行遍历。**故,对这颗树向左遍历,直到指向nullptr.
在这里插入图片描述
在这里插入图片描述
D的左子树为nullptr,D出栈,遍历D节点,访问D的右子树。因为D的右子树为nullptr,故D节点遍历完成。B出栈,遍历B,访问B的右子树

在这里插入图片描述
B的右子树不为nullptr,E入栈,访问E的左子树,因为E的左子树不为nullptr,故G进栈,因为G的左子树为nullptr
,G出栈,遍历G,访问G的右子树,因为G的右子树也为nullptr,G节点遍历完成。
在这里插入图片描述
E出栈,遍历E,访问E的的右子树,E的右子树为nullptr,E节点遍历完成。A出栈,遍历A,访问A的右子树。
在这里插入图片描述
A的右子树不为空,C进栈,访问C的左子树为nullptr,C出栈,遍历C,访问C的右子树,F进栈,因为F的左子树为nullptr,F出栈,遍历F,访问F的右子树,右子树为空,F节点遍历完成。
在这里插入图片描述
栈为nullptr,并且二叉树的每个结点有且仅有一次被访问,遍历完成。
遍历顺序为
在这里插入图片描述
中序遍历记住:节点先入栈,出栈遍历节点,访问节点右子树
算法思想
1.开始访问一棵树根节点
2.向左路节点入栈,直到左路节点为空。
3.栈内节点开始出栈,出栈遍历该节点,访问它的右子树。
4.栈为空,节点全部入栈出栈遍历了一次,结束遍历。

算法实现

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur=root;
        while(cur||!st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            }
            TreeNode*top=st.top();
            v.push_back(top->val);
            st.pop();
            cur=top->right;
        }
        return v;

    }
};

四、 后序遍历(Postorder Traversal)

------访问根结点的操作发生在遍历其左右子树之后

后序遍历图解
依然遍历该颗二叉树
在这里插入图片描述
首先,与前序,中序遍历相同,先访问左子树,向左遍历直到指向nullptr,这时D节点出栈,访问它的右子树。
在这里插入图片描述
在这里插入图片描述
这时D再入栈,访问它的右子树,因为D节点的右子树也为nullptr,D节点再次出栈,遍历D。
在这里插入图片描述
在这里插入图片描述
因为D此时已经访问结束,左右子树都访问完了。B出栈,访问它的右子树,接着B再入栈,因为B的右子树不为nullptr,E入栈。
在这里插入图片描述
因为E的左子树指向nullptr,E出栈访问它的右子树,E再进栈,因为E的右子树不为空,G进栈。
在这里插入图片描述
此时,G的左子树为nullptr,出栈访问,进栈,因为右子树为nullptr,G出栈遍历。G遍历完成,E再次出栈,E的左右子树访问完成,遍历E节点,E遍历完成。B节点再次出栈。左右子树访问完成,遍历B节点,B遍历完成。A节点出栈,访问它的右子树。
在这里插入图片描述
因为A的右子树不为nullptr,C节点入栈,因为C节点的左子树为nullptr,出栈,访问它的右子树,C再进栈,因为C的右子树不为nullptr,故F进栈。
在这里插入图片描述
因为F的左子树为空,出栈,访问右子树,进栈,右子树为nullptr,再次出栈,遍历F节点,F节点遍历完成,C出栈,因为C节点的左右子树都访问完成,C节点出栈,遍历C节点,C遍历完成。A出栈,A的左右子树都访问完成,遍历A节点,A遍历完成,栈为nullptr,遍历结束。
在这里插入图片描述
遍历顺序为
在这里插入图片描述
中序遍历记住:节点先入栈,出栈访问右子树,再进栈,右子树访问完成,再出栈遍历
算法思想
1.开始访问一棵树根节点。
2.向左路节点入栈,直到左路节点为空。
3.栈内节点开始出栈,出栈,访问右子树,再进栈,访问它的右子树,右子树全部访问完成,再出栈遍历。
4.栈为空,节点全部入栈出栈遍历了一次,结束遍历。

算法实现

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur=root;
        TreeNode* prev=nullptr;
        while(cur||!st.empty())
        {
            //左路节点入栈
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            }
            TreeNode*top=st.top();
            //访问栈顶节点的右子树为空,或者上一个访问节点为该节点右子树的根,表示已经访问过了,故可一遍历该栈顶节点。
            if(top->right==nullptr||top->right==prev)
            {
            v.push_back(top->val);
            prev=top;
            st.pop();
            }
            else
            {
            cur=top->right;
            }
        }
        return v;

总结

用非递归的方法去进行前序,中序,后序的遍历是对二叉树遍历的过程更深入的了解。
最后除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在
层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层
上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

图片来自:https://blog.csdn.net/qq_61959780/article/details/127690872

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值