题目描述
解法1-递归法
解题思路:递归法的思路比较简单,就是先遍历左子树,然后访问根结点,然后再遍历右子树。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private ArrayList<Integer> ret = new ArrayList<Integer>();
public List<Integer> inorderTraversal(TreeNode root) {
if(root != null) //若当前结点为空,则返回
{
inorderTraversal(root.left); //遍历左子树
ret.add(root.val); //将根结点的值加入返回的列表
inorderTraversal(root.right); //遍历右子树
}
return ret;
}
}
复杂度
- 时间复杂度:O(n),其中n为二叉树的结点个数
- 空间复杂度:所需辅助空间为树的深度,最坏情况下空间复杂度为O(n),平均情况为O(logn)
解法2-非递归法
解题思路:在遍历左子树之前,先把根结点入栈,当左子树遍历结束后,从栈中弹出并访问,再遍历右子树。
class Solution {
private ArrayList<Integer> ret = new ArrayList<Integer>();
public List<Integer> inorderTraversal(TreeNode root) {
var stack = new Stack<TreeNode>();
TreeNode p = root;
while(p != null || !stack.empty()) //直到当前结点为空,且栈也为空,才表示遍历完成
{
if(p != null) //当前结点不为空,将其入栈,然后遍历其左子树
{
stack.push(p);
p = p.left;
}
else //左子树遍历结束
{
p = stack.pop(); //返回根结点并访问
ret.add(p.val);
p = p.right; //遍历右子树
}
}
return ret;
}
}
复杂度
- 时间复杂度:O(n),其中n为二叉树的结点个数
- 空间复杂度:所需辅助空间为树的深度,最坏情况下空间复杂度为O(n),平均情况为O(logn)
解法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;
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/dong-hua-yan-shi-94-er-cha-shu-de-zhong-xu-bian-li/
复杂度
- 时间复杂度:O(n)。想要证明时间复杂度是O(n),最大的问题是找到每个节点的前驱节点的时间复杂度。乍一想,找到每个节点的前驱节点的时间复杂度应该是O(nlogn),因为找到一个节点的前驱节点和树的高度有关。但事实上,找到所有节点的前驱节点只需要O(n)时间。一棵 n 个节点的二叉树只有 n-1条边,每条边只可能使用2次,一次是定位节点,一次是找前驱节点。故复杂度为O(n)。
- 空间复杂度:O(n)。使用了长度为n的数组。