数据结构:二叉树的非递归遍历

 vector<int> res;
 vector<TreeNode*> tree;
 if (root == NULL) return res;
 TreeNode* p = root;//建立临时指针指向根节点
 while (p||!tree.empty())
 {
     if (p)
     {
         tree.push_back(p);
         res.push_back(p->val);
         p = p->left;
     }
     else
     {
         TreeNode* x = tree.back();
         tree.pop_back();
         p = x->right;//当左子树没有的时候,我们就把栈顶元素弹出,并且读它的右子树
     }
 }
 while (!tree.empty())
 {
     TreeNode* x = tree.back();
     tree.pop_back();
     res.push_back(x->val);
 }
 return res;
}
}

 前序遍历

从根节点开始向左遍历,每一个都又输出又入栈,直到最后一个元素没有左节点。然后开始弹出栈内元素,如果栈内元素有右节点的话,就让临时指针p指向右节点,走那个往左节点遍历的循环。如果栈内元素没有右节点的话,就继续往下弹出栈内元素。

思考:为什么前序遍历会一边入栈一边输出呢?其实这就实现了根节点的先输出。为什么要先从左边这条路往下走呢?其实这就实现了左结点的先输出。为什么我们要一直遍历到左节点没有左节点为止呢,每次输出的时候有右子树右子树又要进入到这个遍历左节点到没有左节点的循环呢,其实这就是实现了递归。

#include<iostream>
#include<vector>
using namespace std;
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> res;
        if (root == NULL) return res;
        vector<TreeNode*> tree;
        TreeNode* p = root;
        while (p || !tree.empty())
        {
            if (p)
            {
                tree.push_back(p);
                p = p->left; 
            }
            else
            { 
                TreeNode* x = tree.back();
                res.push_back(x->val);
                tree.pop_back();
                p = x->right;
            }
          
        }
    }
};

中序遍历

每次入栈的时候不输出,一直往左节点遍历直到没有左节点为止,开始弹出栈,在边弹出的时候边输出。同样也要访问右节点。

#include<iostream>
#include<vector>
using namespace std;
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> res;
        if (root == NULL) return res;
        vector<TreeNode*> tree;
        TreeNode* p = root;
        TreeNode* pre = NULL;
        while (p || !tree.empty())
        {
            if (p)
            {
                tree.push_back(p);
                p = p->left;
            }
            else
            {
                p = tree.back();
                if (p->right == NULL || p->right == pre)//如果这个根节点没有右孩子,又或者右孩子全部遍历过了,才能输出根节点
                {
                    res.push_back(p->val);
                    tree.pop_back();
                    pre = p;
                    p = NULL;
                }
                else
                {
                    p = p->right;
                }
            }
          
        }
        return res;
    }
};

 

 后序遍历

肯定不能边入栈边输出。但是而不能直接在出栈的时候输出,那样就变成中序遍历了。这里注意我们其实是在玩当前栈的右孩子,如果没有孩子或者右孩子已经输出过了,这个时候我们才能输出,并且让p指向空继续弹出栈内元素。如果有右孩子的话,我们要送右孩子进循环。

其实都很相似(就是每次的循环的模板是一样的)。关键是要知道什么时候我们要压入栈,什么时候我们又要输出(也就是这里的res数组)。还有循环的设置问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值