递归 效率极高
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List preorderTraversal(TreeNode root) { List ls = new LinkedList(); per(root, ls); return ls; } public static void per(TreeNode T, List ls) { if (T != null) { ls.add(T.val); if (T.left != null) per(T.left, ls); if (T.right != null) per(T.right, ls); } } }
用了递推接出来 但是效率不高
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List preorderTraversal(TreeNode root) { List ls = new LinkedList(); Stack queue = new Stack(); queue.add(root); while (!queue.isEmpty()) { TreeNode node = queue.pop(); if (node != null) { ls.add(node.val); if (node.right != null) queue.add(node.right); if (node.left != null) queue.add(node.left); } } return ls; } }
莫里斯遍历 不懂
方法 2:莫里斯遍历
方法基于 莫里斯的文章,可以优化空间复杂度。算法不会使用额外空间,只需要保存最终的输出结果。如果实时输出结果,那么空间复杂度是 O(1)O(1)。
算法
算法的思路是从当前节点向下访问先序遍历的前驱节点,每个前驱节点都恰好被访问两次。
首先从当前节点开始,向左孩子走一步然后沿着右孩子一直向下访问,直到到达一个叶子节点(当前节点的中序遍历前驱节点),所以我们更新输出并建立一条伪边 predecessor.right = root 更新这个前驱的下一个点。如果我们第二次访问到前驱节点,由于已经指向了当前节点,我们移除伪边并移动到下一个顶点。
如果第一步向左的移动不存在,就直接更新输出并向右移动。
class Solution { public List preorderTraversal(TreeNode root) { LinkedList output = new LinkedList(); TreeNode node = root; while (node != null) { if (node.left == null) { output.add(node.val); node = node.right; } else { TreeNode predecessor = node.left; while ((predecessor.right != null) && (predecessor.right != node)) { predecessor = predecessor.right; } if (predecessor.right == null) { output.add(node.val); predecessor.right = node; node = node.left; } else{ predecessor.right = null; node = node.right; } } } return output; } }