递归 效率极高
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ls = new LinkedList<Integer>();
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<Integer> preorderTraversal(TreeNode root) {
List<Integer> ls = new LinkedList<Integer>();
Stack<TreeNode> queue = new Stack<TreeNode>();
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<Integer> preorderTraversal(TreeNode root) {
LinkedList<Integer> 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;
}
}