560 字
3 分钟
【算法笔记】(十一)二叉树遍历的非递归实现
先序遍历
- 根节点先入栈
- 每次弹出一个节点就立即访问
- 为了保证左子树先处理,必须先压右,再压左
// 先序打印所有节点,非递归版public static void preOrder(TreeNode head) { if (head != null) { Stack<TreeNode> stack = new Stack<>(); stack.push(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); } } System.out.println(); }}中序遍历
- 一路向左走,经过的节点全部压栈
- 走到最左边后,再开始弹栈访问
- 弹出某个节点之后,再去处理它的右子树
// 中序打印所有节点,非递归版public static void inOrder(TreeNode head) { if (head != null) { Stack<TreeNode> stack = new Stack<>(); while (!stack.isEmpty() || head != null) { if (head != null) { stack.push(head); head = head.left; } else { head = stack.pop(); System.out.print(head.val + " "); head = head.right; } } System.out.println(); }}后序遍历
对于任意一个节点,只有当它的左右子树都处理完了,自己才能出栈被访问,因此核心问题是:怎么判断当前的栈顶节点的左右子树是否已经处理过?使用一个变量 h 来解决这个问题。
// 后序打印所有节点,非递归版public static void posOrderOneStack(TreeNode h) { if (h != null) { Stack<TreeNode> stack = new Stack<>(); stack.push(h); // 如果始终没有打印过节点,h就一直是头节点 // 一旦打印过节点,h就变成打印节点 // 之后h的含义:上一次打印的节点 while (!stack.isEmpty()) { TreeNode cur = stack.peek(); if (cur.left != null && h != cur.left && h != cur.right) { // 当前节点有左子树 // 并且最近处理过的节点不是它的左孩子,也不是它的右孩子 // 说明左右子树都还没处理到,那么先去处理左子树 stack.push(cur.left); } else if (cur.right != null && h != cur.right) { // 左子树已经处理过了,或者根本没有左子树 // 当前有右子树且右子树没有被处理,那么处理右子树 stack.push(cur.right); } else { // 左树、右树 没有 或者 都处理过了,那么当前节点就可以访问 // 访问之后把它记录到h里,表示这是最近一次处理完成的节点 System.out.print(cur.val + " "); h = stack.pop(); } } System.out.println(); }} 【算法笔记】(十一)二叉树遍历的非递归实现
http://hgqwd.icu/posts/suanfa11/ 部分信息可能已经过时









