java非递归遍历二叉树 - Kaiqisan

大家好,都吃晚饭了吗?我是Kaiqisan,是一个已经走出社恐的一般生徒,都说所有的递归都可以使用非递归的方式来解决,所以这次来一起康康非递归版本的二叉树的遍历

递归的本质就是不断往栈中塞入待执行代码,然后在代码块被执行的时候就会被调用执行,直到栈空,所以我们遍历树的时候也需要利用栈结构。

众所周知,前中后序遍历树的方法都很好理解

前序遍历就是先访问自己,再访问左节点最后访问右节点(中左右
中序遍历就是先访问左节点,再访问自己最后访问右节点(左中右
后序遍历就是先访问左节点,再访问右节点最后访问自己(左右中

所以在递归方法遍历的时候就改变一下打印的时机就可以了

所以在转到非递归方法的时候也需要利用这种特点

非递归先序

先让一头结点入栈,然后再开始迭代,每次迭代之前判断一下是否栈空(栈空表示遍历结束)
每次遍历都先把当前出栈节点的右节点入栈,再把当前节点的左节点入栈,为什么要先让右节点先入栈呢?这样可以让先前左节点先出栈,从而实现先序遍历的中左右顺序

	static void searchTree(Tree head) {
        if (head != null) {
            Stack<Tree> stack = new Stack<>();
            stack.add(head); // 元素入栈
            while (!stack.isEmpty()) {
                head = stack.pop(); // 元素出栈
                System.out.print(head.val + " ");
                // 先压右后压左
                if (head.right != null) {
                    stack.push(head.right);
                }
                if (head.left != null) {
                    stack.push(head.left);
                }
            }
        }
    }
以这棵树为例
 *           1
 *          / \
 *         2   3
 *        / \ / \
 *       4  5 6  7
 * 
下面为每次执行的流程(右边为栈头,优先出栈)
stack: 1         print: ""
stack: 32        print: "1"       (1出栈,1的左右孩子入栈)
stack: 354       print: "12"      (同理)
stack: 35        print: "124"     (4无子节点,只是单方面出栈)
stack: 3         print: "1245"
stack: 76        print: "12453"
stack: 7         print: "124536"
stack:           print: "1245367" (栈无元素,结束遍历)

非递归中序

思路:从根节点开始,先无脑遍历左孩子,到头之后,出栈一个元素,回到当前节点未遍历的父节点,然后遍历右孩子,然后接着重复一开始的操作,开始无脑遍历左孩子
这样就可以实现中序遍历的(左中右

	static void searchTree(Tree head) {
        if (head != null) { // 只是判断一个数是否为空树
            Stack<Tree> stack = new Stack<>();
            while (!stack.isEmpty() || head != null) {
                if (head != null) {
                    stack.push(head); // 入栈
                    head = head.left;
                } else {
                    head = stack.pop(); // 出栈
                    System.out.println(head.val);
                    head = head.right;
                }
            }
        }
    }
以这棵树为例
 *           1
 *          / \
 *         2   3
 *        / \ / \
 *       4  5 6  7
 * 
下面为每次执行的流程(右边为栈头,优先出栈)
stack: 1           print: ""
stack: 12          print: ""       
stack: 124         print: ""  (4无左节点,也没有右节点,所以通过出栈节点回到没有被遍历的父节点2)
stack: 12          print: "4"  
stack: 15          print: "42"   
stack: 3           print: "4251"   
stack: 36          print: "4251"  
stack: 3           print: "42516"  
stack: 7           print: "425163"
stack:             print: "4251637"

非递归后序

使用了两个栈,先使用和先序遍历一样的思路来出入栈(假设先入栈1),但是入栈是时候不同于上面的先右后左,这次是先左后右,把栈1出来的元素再放入栈2,最后再把所有栈2的元素
倒出,依次输出。
为什么这么做,仔细看上面的先序和后序的遍历顺序,先序是中左右,后序是左右中,所以先使用中右左的遍历方法,然后再利用第二个栈来倒出元素,把所有的元素翻转,于是就变成了后序的左右中

	static void searchTree4(Tree head) {
        if (head != null) {
            Stack<Tree> stack1 = new Stack<>();
            Stack<Tree> stack2 = new Stack<>();

            stack1.push(head);
            while (!stack1.isEmpty()) {
                head = stack1.pop();// 出栈
                stack2.push(head);	// 入栈
                // 先压左再压右
                if (head.left != null) {
                    stack1.push(head.left);
                }
                if (head.right != null) {
                    stack1.push(head.right);
                }
            }
            // 倒元素
            while (!stack2.isEmpty()) {
                System.out.print(stack2.pop().val); 
            }
        }
    }

如果只用一个栈的方法目前还没想到,敬请期待!

总结

要注意的点还是tmd开头那句话,所有的递归都可以使用非递归的方式来解决,如果在入职考试中写算法题的时候,切记不要使用递归,而且在工程中也是很少使用递归的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kaiqisan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值