关于二叉树非递归后续遍历的一些思考

我们知道,在二叉树的三种遍历方式中,非递归的后续遍历是最难的,但是一个偶然的发现让我觉得二叉树的后序遍历也没有那么难。发生这样转换的关键在于反向思维,具体讲解如下。

以下面的二叉树为例讲解这个问题。

有二叉树如上所示,其前序遍历为:

1 2 4 7 3 5 6 8

其后序遍历为:

7 4 2 5 8 6 3 1

如果我们将后续遍历反过来看(暂时称为反后序遍历),其遍历的顺序为:

1 3 6 8 5 2 4 7

看出来什么问题没有?其实反后序遍历和前序遍历是一样的,唯一的区别是,前序遍历的第二个位置是左节点,而反后序遍历的第二个位置是右节点。还是简单画个图:

对于上面的简单二叉树,前序遍历是:a b c,反后序遍历是:a c b。

有了这一个层面的理解后,我们就可以更“简洁”地实现后续遍历了:1 获取反后序遍历;2 翻转反后序遍历。

而什么说这样简单呢?基于两点原因:1 前序遍历的非递归实现是比较容易的;2 翻转一个序列也是比较容易的。

好吧,说到这里,可以直接上代码了。对于前序遍历的非递归实现,可以这样写:

int PreorderTraverseIteratively(BinaryTreeNode* root) {
    stack<BinaryTreeNode*> node_stack;
    node_stack.push(root);
    while (!node_stack.empty()) {
        BinaryTreeNode* node = node_stack.top();
        node_stack.pop();
        if (node == nullptr) continue;
        cout << "preorcer iteratively: " << node->value << endl;
        node_stack.push(node->right);
        node_stack.push(node->left);
    }
    return RET_SUCCESS;
}

而反后序遍历与前序遍历的区别就是的输出的顺序需要变化;对于翻转,为了使代码显得简洁,我们使用栈来实现这个操作,最终的代码如下:

int PostorderTraverseIterativelyV2(BinaryTreeNode* root) {
    stack<BinaryTreeNode*> node_stack;
    stack<int> output_stack;
    node_stack.push(root);
    while (!node_stack.empty()) {
        BinaryTreeNode* node = node_stack.top();
        node_stack.pop();
        if (node == nullptr) continue;
        output_stack.push(node->value);
        node_stack.push(node->left);
        node_stack.push(node->right);
    }

    while (!output_stack.empty()) {
        cout << "postorder iteratively v2: " << output_stack.top() << endl;
        output_stack.pop();
    }

    return RET_SUCCESS;
}

瞬间感觉比之前对后序遍历的非递归方式的理解清晰了不少,哈哈哈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值