题目
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
输出: [1,3,2]
进阶:
- 递归算法很简单,你可以通过迭代算法完成吗?
解答
解法一:递归
递归遍历没什么难度,这里不细说了。
复杂度:O(n) 时间,O(n) 空间。
代码
/**
* 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> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inOrder(root, res);
return res;
}
private void inOrder(TreeNode node, List<Integer> res) {
if(node == null) return;
inOrder(node.left, res);
res.add(node.val);
inOrder(node.right, res);
}
}
结果
解法二:栈
步骤如下:
- 把当前结点的所有左结点压栈。
- 弹栈时遍历弹出的结点(注意此时弹出的结点的左子树必然已经遍历完毕)。
- 然后对弹出结点的右节点继续遍历。
复杂度:O(n) 时间,O(n) 空间。
代码
/**
* 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> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
LinkedList<TreeNode> stack = new LinkedList<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
res.add(cur.val);
cur = cur.right;
}
return res;
}
}
结果
解法三:线索二叉树(Morris算法)
要点如下:
-
如果当前结点有左子树,那么将左子树的最右结点 pre.right 指向当前结点作为线索。
-
同时将当前结点的 cur.left = null ,目的是再次遍历到当前结点时,说明当前结点的左子树已经遍历完毕了。
优点是省掉了 O(n) 空间的栈,缺点是会改变树的结构。
复杂度:O(n) 时间,O(n) 空间。
代码
/**
* 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> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
TreeNode cur = root;
TreeNode pre;
while(cur != null) {
if(cur.left == null) {
res.add(cur.val);
cur = cur.right;
} else {
pre = cur.left;
while(pre.right != null) {
pre = pre.right;
}
pre.right = cur;
TreeNode temp = cur;
cur = cur.left;
temp.left = null;
}
}
return res;
}
}
优化代码:不改变树的结构
大体思想是:当再次遍历到 cur 时,判断 cur 左子树的最右结点 pre.right 是否等于 cur ,从而判断其左子树是否已经全部遍历。
显而易见,时间上并没有改变树结构的方法高效。
但优点是遍历并不会改变树的结构!!!
只是遍历而已,却把树结构改变了是什么鬼 :)
我觉得还是有必要优化一下。。。
/**
* 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> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
TreeNode cur = root;
TreeNode pre;
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;
}
if(pre.right == cur) {
pre.right = null;
res.add(cur.val);
cur = cur.right;
}
}
}
return res;
}
}