思路
上一篇博文咱们讲了二叉树的递归算法,这里咱们来写一波二叉树的非递归算法java
为何说遍历二叉树能够用递归node
二叉树每一个结点都知足某个遍历次序,而后从根结点开始遍历,这个流程很是知足递归的模型,就是一个大的问题按照某种方式能够划分为许多细小的问题,而后这些细小的问题又能够用一样的方式继续划分,直到为空或者说直到有个出口算法
全部递归能够转化成非递归数组
那非递归我该如何实现呢?这就不得不从递归的有一个特色提及了,递归老是这样的形式:a<b<c<d
,a 表示第一层方法,b 表示第二层的递归,c 表示第三层的递归,d 表示第四层的递归,那么咱们程序运行的效果确定是:a 到 b 到 c 到 d,而后 d 找到出口所有执行完了,返回 c,c 又所有执行完了,再到 b,b 所有执行完了,再到 a,也就是 a→b→c→d→d→c→b→a 的次序,这不就是栈的数据结构吗???对了,就是栈,所以若是咱们不用递归,那咱们确定得用循环再加上栈的使用数据结构
先序&中序和后序有什么不一样ide
咱们知道先序是根左右,中序是左根右,后序是左右根,先序和中序没啥大的花样,可是后续有些不一样,为何呢?由于对于先序遍从来讲,最早记录结点的数据,而后能找到左结点就一直找左结点,找不到能够再找栈顶的右结点,并同时释放栈顶结点;若是是中序的话,先找左结点,找不到为止,就记录栈顶结点的值,释放栈顶结点,同时再去找该栈顶结点的右结点;可是对后序遍历可不一样了,由于后序是先去找左结点,一直到找不到为止,咱们再去找栈顶的右结点,可是要注意的是后序遍历在左右结点转换的时候,咱们并不知道这个根结点何时弹出栈顶,最大的不一样就在于这里。先序和中序在左结点找不到时切换右结点时候会弹出根结点,根结点这颗棋子已经没有用了,可是后序遍历可不这样,当左结点实在找不到时候,去找栈顶的右结点,此时栈顶结点还不能获得释放,由于右结点的后序遍历没有找尽每个结点,因此还不能记录该根结点的值post
后序遍历算法的思路this
若是咱们找的到左结点就一直找,找不到的话,咱们拿到栈顶结点,看栈顶的右结点是否找的到,找的到的话,那就指向右结点,而后继续按照后序遍历的模式,若是栈顶的右结点找不到,那么咱们就记录栈顶的结点,并弹出栈顶结点,而后咱们将新结点令为空,这样下次会重新栈顶结点往右边找。这样这个算法好像就完了是否是?不是,这里有个很大的漏洞!我举个例子说明:假如咱们一直找左结点找到了 a 结点,而后 a 结点的左结点为 null,a 结点的右结点是 b 结点,b 结点的左结点为 null,b 结点的右结点也为 null,当咱们找到 a 结点时候,按照上面的算法思路,a->left 为空,可是栈顶结点 a 的右结点 b 不为空,因此新结点是 b 并入栈,b 的左结点为空,而后栈顶结点 b 的右结点为空,b 又变成了 a 结点,发现了吗?这不返回的了吗?这不从 a 到 b,b 又到 a,这不没完没了了?因此算法漏洞是咱们少加了一个东西,咱们应该在当咱们右结点找不到时,须要记录栈顶的结点,而且当下一次循环访问右结点时,右结点不只不为空,并且右结点不能是上次循环中弹出的那个结点!code
Java 实现// 结点 class Node { int data; Node left = null; Node right = null; } // 二叉树 public class BinaryTree { // 根结点 private Node root; // 输入的数组 private int[] arr_in; // 输出的数组 private int[] arr_out; // 记录数组下标 private static int index; // 初始化 public BinaryTree(int[] arr) { root = new Node(); this.arr_in = arr; arr_out = new int[arr.length]; index = 0; } // 先序遍历二叉树(非递归)根→左→右 public int[] preorderTraversal(Node r) { Stack stack = new Stack(); Node node = r; while (!stack.empty() || node != null) { if (node != null) { stack.push(node); // 根 arr_out[index++] = node.data; // 左 node = node.left; } else { Node top = stack.pop(); // 右 node = top.right; } } index = 0; return arr_out; } // 中序遍历二叉树(非递归)左→根→右 public int[] inorderTraversal(Node r) { Stack stack = new Stack(); Node node = r; while (!stack.empty() || node != null) { if (node != null) { stack.push(node); // 左 node = node.left; } else { Node top = stack.pop(); // 根 arr_out[index++] = top.data; // 右 node = top.right; } } index = 0; return arr_out; } // 后序遍历二叉树(非递归)左→右→根 public int[] postorderTraversal(Node r) { Stack stack = new Stack(); Node node = r; Node top = null; while (!stack.empty() || node != null) { if (node != null) { stack.push(node); // 左 node = node.left; } else { if (stack.peek().right != null && stack.peek().right != top) // 右 node = stack.peek().right; else { top = stack.pop(); // 根 arr_out[index++] = top.data; node = null; } } } index = 0; return arr_out; } }