辛星Java树算法教程第三篇:树的后序遍历(递归方式与非递归方式的双栈方式)

到现在,树的深度遍历方式中就剩下树的后序遍历方式了,后序遍历也是三种遍历方式里面相对比较难的一个,也是思路相对比较多的一个。

对于后序遍历,我们先给出一个递归的解法:

package com.mengzhidu.teach.algorithm.tree.demo.traversal;

import com.mengzhidu.teach.algorithm.tree.demo.TreeNode;
import com.mengzhidu.teach.algorithm.tree.demo.TreeNodeHelper;

/**
 * Created by xinxing on 2019/3/20
 */
public class PostOrderDemo1 {

    public static void main(String[] args) {
        postOrder(TreeNodeHelper.getTreeNode());
    }

    private static void postOrder(TreeNode treeNode) {
        if (treeNode == null) {
            return;
        }
        postOrder(treeNode.getLeft());
        postOrder(treeNode.getRight());
        System.out.println(treeNode.getValue());
    }
}

递归的解法是比较简单的,然后我们来思考一下非递归方式的实现,有很多种实现方式,比较常见的方式有两种,第一种是使用两个栈来实现,第二种是使用一个栈来实现。

其实使用两个栈来实现,也有两种常见的实现方式。我们分别来看一下:

我们来看一下使用两个栈来实现的方式,它的思考机制为:
(1).一个栈用来标记当前处理的节点,我们不妨记做栈1,一个栈我们用来存储所有的结果,它这里的存储是反向的结果。
(2).我们在处理一个节点的时候,首先把它的根节点压到两个栈里面,然后压入右子树的根节点,接下来就一直压入右子树。
(3).直到没有右子树可以压了,我们就弹出栈1的元素,把它的左子树的根节点压到栈1和栈2里面,直到它的右子树也被压完。
(4).这样,我们用栈1来标识当前的临时节点,我们用栈2来标识整个的结果集。
我们来看一下具体的结果实现吧:

package com.mengzhidu.teach.algorithm.tree.demo.traversal;

import com.mengzhidu.teach.algorithm.tree.demo.TreeNode;
import com.mengzhidu.teach.algorithm.tree.demo.TreeNodeHelper;

import java.util.Stack;

/**
 * 基于双栈法实现的后序遍历
 * Created by xinxing on 2019/3/20
 */
public class PostOrderDemo2 {

    public static void main(String[] args) {
        Stack <TreeNode> stack1 = new Stack<>();
        Stack <TreeNode> stack2 = new Stack< >();
        TreeNode cur = TreeNodeHelper.getTreeNode();

        while(cur != null || !stack1.isEmpty()) {
            while (cur != null) {
                stack1.push(cur);
                stack2.push(cur);
                cur = cur.getRight();
            }
            cur = stack1.pop();
            cur = cur.getLeft();
        }

        while(!stack2.isEmpty()) {
            System.out.println(stack2.pop().getValue());
        }

    }
}

第二种思路也是使用两个栈,它也是使用一个栈来保存当前的指向,用一个栈来保存结果集,只不过这个结果集是和后序遍历是反着的,比如后序遍历最后保存根节点,它就先存储根节点,后序遍历倒数第二个元素是根节点的右子树的元素,它就第二个保存根节点的右子树的元素。
如果把树做一个镜像,也就是所有的节点的左右子树都进行一次交换的话,那么后序遍历可以看做是前序遍历的反过程。
说了这么多,还是来看一段代码吧:

package com.mengzhidu.teach.algorithm.tree.demo.traversal;

import com.mengzhidu.teach.algorithm.tree.demo.TreeNode;
import com.mengzhidu.teach.algorithm.tree.demo.TreeNodeHelper;

import java.util.Stack;

/**
 * 基于双栈实现的方法
 * Created by xinxing on 2019/3/22
 */
public class PostOrderDemo3 {

    public static void main(String[] args) {
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        TreeNode root = TreeNodeHelper.getTreeNode();
        stack1.push(root);

        while (!stack1.isEmpty()) {
            root = stack1.pop();
            if (root == null) {
                continue;
            }
            stack2.push(root);
            stack1.push(root.getLeft());
            stack1.push(root.getRight());
        }

        while (!stack2.isEmpty()) {
            System.out.println(stack2.pop().getValue());
        }
    }
}

至此,我们使用两个栈来进行后序遍历的方式就介绍完了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值