给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:输入:root = []
输出:[]
示例 3:输入:root = [1]
输出:[1]
题目来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/binary-tree-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
首先我们要知道关于二叉树的中序遍历的意思是指按照:访问左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归的性质,我们可以直接用递归函数来模拟这一过程。
方法一:递归
定义一个方法inorder(TreeNode root, List<Integer> result)来实现链表的递归遍历。先遍历节点左子树,再将节点加入集合,后遍历节点右子树,直到节点为空。
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result=new ArrayList<Integer>();
inorder(root,result);//递归遍历链表
return result;
}
private void inorder(TreeNode root, List<Integer> result) {
if(root==null) {//当节点为空时,停止遍历
return;
}
inorder(root.left, result);//先遍历左子树
result.add(root.val);//将节点添加进去
inorder(root.right, result);//再遍历右子树
}
方法二:迭代
和递归方式一样,但创建了一个栈来作为中间存储,节点不为空或者栈不为空时,遍历让节点进栈并遍历左子树,直到节点为空,节点出栈,将节点值添加到集合中,再遍历右子树,直到遍历完整个树。
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<Integer>();
Stack<TreeNode> stack=new Stack<TreeNode>();//利用一个栈作为零时存储结果
while(root!=null||!stack.isEmpty()) {
while(root!=null) {//当节点不为空时,将节点进栈,且让节点指向左子节点
stack.push(root);
root=root.left;
}
root=stack.pop();//节点出栈
list.add(root.val);//将节点的值添加到集合中
root=root.right;//将节点指向右子节点
}
return list;
}
方法三:
遍历树,判断当前节点是否还有左孩子,如果有,遍历左子树,找到左子树上最右的节点,记录该节点为predecessor,再判断该节点是否没有右孩子,如果有,则指向其右孩子,再访问左孩子,如果还有右孩子,则说明已经遍历完左子树,将右孩子置空,再将节点加入结果集合;如果当前节点没有左孩子,则将节点加入结果集,再访问右孩子。
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
TreeNode predecessor = null;
while (root != null) {
if (root.left != null) {// 当左节点不为空时
predecessor = root.left;
// predecessor节点就是当前 root节点向左走一步,然后一直向右走至无法走为止
while (predecessor.right != null && predecessor.right != root) {
predecessor = predecessor.right;
}
// 让 predecessor 的右指针指向 root,继续遍历左子树
if (predecessor.right != null) {
predecessor.right = root;
root = root.left;
}
// 说明左子树已经访问完了,我们需要断开链接
else {
res.add(root.val);
predecessor.right = null;
root = root.right;
}
}
// 如果没有左孩子,则直接访问右孩子
else {
res.add(root.val);
root = root.right;
}
}
return res;
}