给定一个二叉树,返回它的中序 遍历。
输入: [1,null,2,3] 1 2 / 3 输出: [1,3,2]
1.最简单也是最直接的,直接用递归算法实现
class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList(); dfs(root,result); return result; } public void dfs(TreeNode root, List list) { if(root == null) { return; } dfs(root.left, list); list.add(root.val); dfs(root.right, list); } }
缺点:
效率低下
2.用迭代模拟递归
class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList(); Stack<TreeNode> stack = new Stack(); while(stack.size() > 0 || root != null) { if(root != null) { stack.add(root); root = root.left; } else { root = stack.pop(); result.add(root.val); root = root.right; } } return result; } }
缺点:
效率低下
3.莫里斯遍历
用递归和迭代的方式都使用了辅助的空间,而莫里斯遍历的优点是没有使用任何辅助空间。
缺点是改变了整个树的结构,强行把一棵二叉树改成一段链表结构。
class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<Integer>(); TreeNode pre = null; while(root!=null) { //如果左节点不为空,就将当前节点连带右子树全部挂到 //左节点的最右子树下面 if(root.left!=null) { pre = root.left; while(pre.right!=null) { pre = pre.right; } pre.right = root; //将root指向root的left TreeNode tmp = root; root = root.left; tmp.left = null; //左子树为空,则打印这个节点,并向右边遍历 } else { res.add(root.val); root = root.right; } } return res; } }
进阶
颜色标记法
其核心思想如下:
使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
如果遇到的节点为灰色,则将节点的值输出。
class Solution { class ColorNode { TreeNode treeNode; String color; public ColorNode(String color, TreeNode treeNode) { this.treeNode = treeNode; this.color = color; } } public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList(); if(root == null) { return result; } Stack<ColorNode> stack = new Stack(); stack.push(new ColorNode("white", root)); while(stack.size() > 0) { ColorNode colorNode = stack.pop(); if("white".equals(colorNode.color)) { if(colorNode.treeNode.right != null) { stack.add(new ColorNode("white", colorNode.treeNode.right)); } stack.add(new ColorNode("grey", colorNode.treeNode)); if(colorNode.treeNode.left != null) { stack.add(new ColorNode("white", colorNode.treeNode.left)); } } else { result.add(colorNode.treeNode.val); } } return result; }
如要实现前序、后序遍历,只需要调整左右子节点的入栈顺序即可。