走歪了的后序遍历非递归写法——模拟递归

最近复习了后续遍历的非递归实现,就算已经看过很多遍了,自己手搓的时候也得想一会。

最开始发明非递归遍历二叉树的人到底是怎么想的啊啊啊啊

琢磨了一段时间,想出了一种以递归方式思考的编码方法,至少对我自己来说比较好理解
但好像有种走歪了的感觉

一、思路

众所周知,最简单的写法是这样的

void postOrderTraversal(TreeNode* root)
{
    if(!root) return;
    postOderTraversal(root->left);
    postOderTraversal(root->right);
    visit(root);    
}

函数的调用都在栈上进行,调用函数时会压栈,同时也会保存当前函数执行的一些信息(形参之类的),以下代码的行为与真正的函数调用可能有差别,都是笔者自己的理解

二、代码

成员函数:

void postOderTraversal()
{
    //简单包装一下,使节点能够储存信息
    struct Node
    {
        TreeNode *tree_node;
        int step;
        Node(TreeNode *t) : tree_node(t), step(1) {}
        operator bool() {return tree_node != nullptr;}//使Node对象能用作判断条件
        void go_right() {tree_node = tree_node->right;}//成员指针向右走         
        void go_left() {tree_node = tree_node->left;}
    };

    Node root(this->root);
    stack<Node> s;
    s.push(root);

    while (!s.empty())
    {
        root = s.top(); // root:正在执行的函数的形参

        if (!root) //传入了空指针,在递归写法里,函数返回(出栈)
        {
            s.pop();
            continue;
        }

        //每次都检查函数执行的步骤
        if (root.step == 1) //函数准备执行第一步postOderTraversal(root->left);
        {
            s.top().step = 2; //当前函数的下一步执行第二步

            // root将被压栈,将被压栈的是新函数调用,所以要“初始化”形参和执行步骤
            root.go_left();
            root.step = 1;
            s.push(root); //压入新函数
        }
        else if (root.step == 2) //与上面同理
        {
            s.top().step = 3;
            root.go_right();
            root.step = 1;
            s.push(root);
        }
        else if (root.step == 3) //函数准备执行第三步visit(root)
        {
            cout << root.tree_node->val << " ";
            s.pop(); //执行完出栈
        }
    }
}

完整测试代码:

测试用了二叉搜索树(比较好插入)

#include <iostream>
using std::cout;using std::endl;

#include <stack>
using std::stack;

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 binTree
{
private:
    TreeNode *bin_add(TreeNode *root, int val)
    {
        if (!root)
            return new TreeNode(val);
        if (val < root->val)
        {
            root->left = bin_add(root->left, val);
        }
        else
        {
            root->right = bin_add(root->right, val);
        }
        return root;
    }

public:
    TreeNode *root;
    binTree(int val)
    {
        root = new TreeNode(val);
    }
    binTree &add(int val)
    {
        root = bin_add(root, val);
        return *this;
    }

    //需要声明pre变量以记录右节点是否刚刚被访问
    //或者创建新类保存执行步骤信息
    void postOderTraversal()
    {
        //简单包装一下,使节点能够储存信息
        struct Node
        {
            TreeNode *tree_node;
            int step;
            Node(TreeNode *t) : tree_node(t), step(1) {}
            operator bool() { return tree_node != nullptr; }  //使Node对象能用作判断条件
            void go_right() { tree_node = tree_node->right; } //成员指针向右走
            void go_left() { tree_node = tree_node->left; }
        };

        Node root(this->root);
        stack<Node> s;
        s.push(root);//栈顶是“当前函数”,即递归函数的第一层
        while (!s.empty())
        {
            root = s.top(); // root:正在执行的函数的形参

            if (!root) //传入了空指针,在递归写法里,函数返回(出栈)
            {
                s.pop();
                continue;
            }

            //每次都检查函数执行的步骤
            if (root.step == 1) //函数准备执行第一步postOderTraversal(root->left);
            {
                s.top().step = 2; //下一步执行第二步

                // root将被压栈,将被压栈的是新函数调用,所以要“初始化”形参和执行步骤
                root.go_left();
                root.step = 1;
                s.push(root); //压入新函数
            }
            else if (root.step == 2) //与上面同理
            {
                s.top().step = 3;
                root.go_right();
                root.step = 1;
                s.push(root);
            }
            else if (root.step == 3) //函数准备执行第三步visit(root)
            {
                cout << root.tree_node->val << " ";
                s.pop(); //执行完出栈
            }
        }
    }

    void postOderTraversal_(TreeNode *r)//递归写法
    {
        if (!r) return;
        postOderTraversal_(r->left);
        postOderTraversal_(r->right);
        cout << r->val << " ";
    }
};

int main(int argc, char const *argv[])
{

    /**
     *                3
     *             1     5
     *           0   2     7
     *                   6
     *
     */
    binTree bt(3);
    bt.add(5).add(1).add(7).add(6).add(0).add(2);

    bt.postOderTraversal_(bt.root);//递归写法
    cout << endl;
    bt.postOderTraversal();//非递归写法
    cout << endl;

    return 0;
}

输出:

0 2 1 6 7 5 3 
0 2 1 6 7 5 3 

c++新手,有错误和不规范的地方希望指出,便于学习改进! 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值