二叉树的遍历方式包括前序遍历、中序遍历和后序遍历,其实现方式包括递归实现和非递归实现。java
前序遍历:根节点 | 左子树 | 右子树node
中序遍历:左子树 | 根节点 | 右子树post
后序遍历:左子树 | 右子树 | 根节点指针
递归方式实现代码十分简洁,三种遍历方式的递归实现代码结构相同,只是执行顺序有所区别。code
前序遍历:递归
public class preOrderRecur { List<Integer> res = new ArrayList<>(); public List<Integer> preOrderTraversal(TreeNode root) { if (root != null) { res.add(root.val); // 根节点 preOrderTraversal(root.left); // 左子树 preOrderTraversal(root.right); // 右子树 } return res; } }
中序遍历:class
public class inOrderRecur { List<Integer> res = new ArrayList<>(); public List<Integer> inOrderTraversal(TreeNode root) { if (root != null) { inOrderTraversal(root.left); // 左子树 res.add(root.val); // 根节点 inOrderTraversal(root.right); // 右子树 } } return res; }
后序遍历:List
public class inOrderRecur { List<Integer> res = new ArrayList<>(); public List<Integer> inOrderTraversal(TreeNode root) { if (root != null) { inOrderTraversal(root.left); // 左子树 inOrderTraversal(root.right); // 右子树 res.add(root.val); // 根节点 } } return res; }
public class inOrderIterator { List<Integer> res = new ArrayList<>(); public List<Integer> inOrderTraversal(TreeNode root) { Stack<TreeNode> stack = new Stack<>(); while (root != null || !stack.isEmpty()) { if (root != null) { stack.push(root); root = root.left; } else { TreeNode node = stack.pop(); res.add(node.val); root = node.right; } } return res; } }
方法1:由于前序遍历访问顺序是“中-左-右”,因此能够先将根结点压栈,而后按照下列步骤执行。二叉树
public class preOrderIterator { List<Integer> res = new ArrayList<>(); public List<Integer> inOrderTraversal(TreeNode root) { if (root == null) return res; Stack<TreeNode> stack = new Stack<>(); stack.push(root); while (!stack.isEmpty()) { root = stack.pop(); res.add(root.val); // 右孩子压栈 if (root.right != null) stack.push(root.right); // 左孩子压栈 if (root.left != null) stack.push(root.left); } return res; } }
方法2:根据中序遍历进行微调:搜索
public class preOrderIterator { List<Integer> res = new ArrayList<>(); public List<Integer> inOrderTraversal(TreeNode root) { Stack<TreeNode> stack = new Stack<>(); while (root != null || !stack.isEmpty()) { if (root != null) { res.add(root.val); stack.push(root); root = root.left; } else { TreeNode node = stack.pop(); root = node.right; } } return res; } }
由于前序遍历的顺序是“左-中-右”,然后序遍历顺序是“左-右-中”,不考虑左结点,区别只是在于中结点和右结点的顺序进行了反向而已,所以可使用前序遍历的代码进行调整,只须要将前序遍历对左右孩子压栈的顺序反向便可,即先压入左孩子,再压入右孩子。除此以外,由于按照这种方法调整获得的遍历顺序为“中-右-左”,正好是后序遍历的反向顺序,所以在得到遍历序列后还需进行逆序操做。
public class postOrderIterator { List<Integer> res = new LinkedList<>(); public List<Integer> postOrderTraversal(TreeNode root) { if (root == null) return res; Stack<TreeNode> stack = new Stack<>(); stack.push(root); while (!stack.isEmpty()) { root = stack.pop(); // 头插法 res.add(0, root.val); // 左孩子压栈 if (root.left != null) stack.push(root.left); // 右孩子压栈 if (root.right != null) stack.push(root.right); } return res; } }
该方法的思路简单说就是,对于每个结点,找到它左孩子的最右子结点,由于按照正常访问顺序,其左孩子的最有子节点访问完后就应该访问其自己了,所以将其左孩子最右子节点的右指针指向它。基本步骤以下:
该方法虽然保证了O(1)的空间复杂度,但在遍历过程当中改变了部分结点的指向,破坏了树的结构。
public class inOrderMorris { List<Integer> res = new ArrayList<>(); public List<Integer> inOrderTraversal(TreeNode root) { TreeNode pre = null; TreeNode cur = root; while (cur != null) { if (cur.left == null) { res.add(cur.val); cur = cur.right; } else { pre = cur.left; while (pre.right != null && pre.right != cur) pre = pre.right; if (pre.right == null) { pre.right = cur; cur = cur.left; } else { res.add(cur.val); pre.right = null; cur = cur.right; } } } return res; } }
public class preOrderMorris { List<Integer> res = new ArrayList<>(); public List<Integer> preOrderTraversal(TreeNode root) { TreeNode pre = null; TreeNode cur = root; while (cur != null) { if (cur.left == null) { res.add(cur.val); cur = cur.right; } else { pre = cur.left; while (pre.right != null && pre.right != cur) pre = pre.right; if (pre.right == null) { res.add(cur.val); pre.right = cur; cur = cur.left; } else { pre.right = null; cur = cur.right; } } } return res; } }
前序遍历反向的思想
public class postOrderMorris { List<Integer> res = new LinkedList<>(); public List<Integer> postOrderTraversal(TreeNode root) { TreeNode pre = null; TreeNode cur = root; while (cur != null) { if (cur.right == null) { res.add(0, cur.val); cur = cur.left; } else { pre = cur.right; while (pre.left != null && pre.left != cur) pre = pre.left; if (pre.left == null) { res.add(0, cur.val); pre.left = cur; cur = cur.right; } else { pre.left = null; cur = cur.left; } } } return res; } }