二叉树的前中后序遍历-----非递归迭代实现 面试冲冲冲!!!

目录

一、二叉树的前中后序遍历概念

(一)前序遍历

(二)中序遍历

(三)后序遍历

(四)层序遍历

二、二叉树前序遍历

(一)题目描述

(二)思路

(三)程序实现

三、二叉树中序遍历

(一)题目描述

(二)思路

(三)程序实现

四、二叉树后序遍历

(一)题目描述

(二)思路

(三)程序实现

 


  • 以下是整理了一晚上的二叉树三种非递归遍历方式,关于非递归遍历,有一个大的特点就是代码简单,但是难以理解。面试中常常考察我们的非递归迭代实现,而主要以后序遍历为重点!!

一、二叉树的前中后序遍历概念

要遍历,首先得有一棵树,直接上图!

(一)前序遍历

依次遍历    根->左子树->右子树,根在头部,故也称为前序遍历。一个原则,当你在某一颗子树中不知道怎么走的时候,永远按照 根->左子树->右子树顺序走就不会错。

上图前序遍历顺序为:8  3  1  6  4  7  10  14  13

(二)中序遍历

依次遍历    左子树->根->右子树,根在中部,故也称为中序遍历。

上图前序遍历顺序为:1  3  4  6  7  8  10  13  14

(三)后序遍历

依次遍历    左子树->右子树->根,根在尾部,故也称为后序遍历。

上图前序遍历顺序为:1  4  7  6  3  13  14  10  8

(四)层序遍历

依次遍历    每一层,故也称为层序遍历。

上图前序遍历顺序为:8 3 10 1 6 14 4 7 13

二、二叉树前序遍历

(一)题目描述

(二)思路

1.我们还是拿上边的二叉树进行讲解,列出该树前序遍历为8 3 1 6 4 7 10 14 13。

2.在非递归中我们需要定义一个栈来存储入栈的结点,在定义一个vector容器来保存遍历的值。而后先访问该树的所有左路节点,将其入栈并将值存储vector中。如下图:

3.接下来需要访问所有的子路节点的右树了,如图将1出栈,判断该结点有没有右树,没有继续将3出栈继续判断,3在走右树,则继续将6入栈,4入栈,也就是再去找子树的每一个左路结点,然后在入栈,每次入之前都存入该结点的数值到vector中,当栈为空并且结点为空时,证明前序遍历已经结束了,直接打印vector的值就是前序遍历的结果了。

(三)程序实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode* cur=root;
        //cur不为空,表示还有树没有开始访问
        //st不为空,表示还有节点得右子树没有访问
        while(cur||!st.empty())
        {
            //将该树中所有的左路结点入栈并将值存储到vector中
            while(cur)
            {
                v.push_back(cur->val);
                st.push(cur);
                cur=cur->left;
            }
           //出栈,并走将该结点的右树 
            cur=st.top();
            st.pop();
            cur=cur->right;
        }
        return v;
    }
};

 

三、二叉树中序遍历

(一)题目描述

(二)思路

1.理解上一个前序遍历,中序也就好理解了,列出该树中序遍历为1  3  4  6  7  8  10  13  14。

2.定义一个vector和栈,依次让所有左路结点入栈,但是先不存入vector中。

3.出栈并访问右子树时,将出栈的值存入vector中,如一开始访问到1时,1没有右树了,所以将1所在的结点出栈并存入1的值。在将3出栈并存值,3有右树则继续访问该右树,将该右树所有左结点入栈,如此循环往复。

4.直至所有结点访问完并且栈为空,遍历就完成了。

(三)程序实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode* cur=root;
        //cur不为空,表示还有树没有开始访问
        //st不为空,表示还有节点得右子树没有访问
        while(cur||!st.empty())
        {
            //将该树中所有的左路结点入栈
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            }
           //出栈,将值存储到vector中,并走该结点的右树 
            cur=st.top();
            v.push_back(cur->val);
            st.pop();
            cur=cur->right;
        }
        return v;
    }
};

四、二叉树后序遍历

(一)题目描述

该题的非递归解法面试过程中常考,是重中之重,因为掌握了后序相当于前序中序全部掌握了。

(二)思路

1.列出该树后序遍历为1  4  7  6  3  13  14  10  8,依次将所有子树左路径入栈,

2.当走到1时,1没有左右树,所以将1出栈并存储,接着判断3是否有右子树,有则转换为子树问题继续访问,接着将4和6入栈。判断4是否有右子树,没有直接出栈并存储,接着我们判断6是否有右子树,有转入子树问题进行入栈,在判断7是否有左右子树,没有则出栈,再次回到6这个节点上。这时我们发现一个问题,我们两次经过6,第一次经过的时候,6的右树还没有访问,第二次在经过6的时候6的右树已经访问了,这时将6出栈并存储。所以,凡是右不为空,都会两次经过这个节点,那么我们要想办法区分。

3.区分两次经过的结点是否出栈存储,如结点6结点3,如果一个节点的右不为空。

  • 如果他的右孩子不等于上一个访问的节点,那么他的右树还没有访问,应该子问题访问。
  • 如果他的右孩子等于上一个访问的节点,那么他的右树已经访问过了,应该放他本身。
  • 相当于当第一次经过6时我们是刚访问完4,并没有访问7,判断条件就是看上一次访问的4是否等于6的右子树结点。所以我们不需要将6出栈并存储,当访问完7时,证明已经访问完6的所有子树了,这时我们就让6出栈并存储,判断条件就是看上一次访问的7是否等于6的右子树结点。

4.直至所有结点访问完并且栈为空,遍历就完成了。

(三)程序实现

 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode* cur=root;
        TreeNode* prev=nullptr;
        //cur不为空,表示还有树没有开始访问
        //st不为空,表示还有节点得右子树没有访问
        while(cur||!st.empty())
        {
            //将该树中所有的左路结点入栈
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            } 
            cur=st.top();
            //判断该结点右子树是否为空,为空则出栈并存储数据
            //判断该结点右子树是否与上一次出栈数据相同,相同则则出栈并存储数据
            if(cur->right==nullptr||cur->right==prev)
            {
                v.push_back(cur->val);
                st.pop();
                prev=cur;
                cur=nullptr;
            }
            //转入子树问题求解
            else
            {
                cur=cur->right;
            }

        }
        return v;
    }
};

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ishao97

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值