中序遍历(LDR)是 二叉树遍历 的一种,也叫做 中根遍历 、中序周游。 在二叉树中,中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。 中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。
算法思想:按照访问左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归的性质,我们可以直接用递归函数来模拟这一过程。定义 inorder(root) 表示当前遍历到 root 节点的答案,那么按照定义,我们只要递归调用 inorder(root.left) 来遍历 root 节点的左子树,然后将 root 节点的值加入答案,再递归调用inorder(root.right) 来遍历 root 节点的右子树即可,递归终止的条件为碰到空节点。
解法一:利用递归思想
public class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List res=new ArrayList();//用于返回节点顺序
inorder(root,res);
return res;
}
public void inorder(TreeNode root,List res){
if (root==null){
return;
}//节点为空是递归退出的条件
inorder(root.left,res);//先寻找左节点
res.add(root.val);
inorder(root.right,res);
}
}
解法二:迭代利用辅助栈
方法一的递归函数我们也可以用迭代的方式实现,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其他都相同,具体实现可以看下面的代码。
public List<Integer> inorderTraversal(TreeNode root) {
List res=new ArrayList();
Deque<TreeNode> stack=new LinkedList();
while (root!=null||!stack.isEmpty()){
while (root!=null){//先把节点的左节点都添加入栈
stack.push(root);
root=root.left;
}//退出循环说明此时节点的左节点是null,那么我们从栈中弹出一个元素,添加入返回的list
root=stack.pop();//获得节点入list
res.add(root.val);
root=root.right;//查看此时root是不是null,不是null就进入循环,是null,root就重新从栈中弹出元素
}
return res;
}
解法一:递归
首先我们需要了解什么是二叉树的前序遍历:按照访问根节点——左子树——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归的性质,我们可以直接用递归函数来模拟这一过程。
定义 preorder(root) 表示当前遍历到 root 节点的答案。按照定义,我们只要首先将 root 节点的值加入答案,然后递归调用 preorder(root.left) 来遍历 root 节点的左子树,最后递归调用 preorder(root.right) 来遍历 root 节点的右子树即可,递归终止的条件为碰到空节点。
public List<Integer> preorderTraversal(TreeNode root) {
List res=new ArrayList();//用于返回
order(root,res);
return res;
}
private void order(TreeNode root, List res) {
if (root==null){
return;
}
res.add(root.val);
order(root.left,res);
order(root.right,res);
}
解法二:迭代利用辅助栈
我们也可以用迭代的方式实现方法一的递归函数,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其余的实现与细节都相同,具体可以参考下面的代码。
public class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List res=new ArrayList();
Deque<TreeNode> stack=new LinkedList();
while (root!=null||!stack.isEmpty()){
while (root!=null){
res.add(root.val);//按照前序遍历顺序
stack.push(root);
root=root.left;
}//退出循环说明当前节点是Null,我们需要从栈中弹出一个元素
root=stack.pop();
root=root.right;
}
return res;
}
}
解法一:递归思想
首先我们需要了解什么是二叉树的后序遍历:按照访问左子树——右子树——根节点的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归的性质,我们可以直接用递归函数来模拟这一过程。
定义 postorder(root) 表示当前遍历到 root 节点的答案。按照定义,我们只要递归调用 postorder(root->left) 来遍历 root 节点的左子树,然后递归调用 postorder(root->right) 来遍历 root 节点的右子树,最后将 root 节点的值加入答案即可,递归终止的条件为碰到空节点。
public List<Integer> postorderTraversal(TreeNode root) {
List res=new ArrayList();
order(root,res);
return res;
}
private void order(TreeNode root, List res) {
if (root==null){
return;
}
order(root.left,res);//先左再右最后自己
order(root.right,res);
res.add(root.val);
}
解法二:迭代利用辅助栈
我们也可以用迭代的方式实现方法一的递归函数,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其余的实现与细节都相同,具体可以参考下面的代码。
public List<Integer> postorderTraversal(TreeNode root) {
List res=new ArrayList();
Deque<TreeNode> stack=new LinkedList();
TreeNode pre=null;//上一个list添加进入的元素,查看右节点是不是被添加过了
while (root!=null||!stack.isEmpty()){
while (root!=null){
stack.push(root);
root=root.left;
}//退出循环说明此时root是null
root=stack.pop();//从栈中弹出一个元素
if (root.right==null||root.right==pre){//没有右节点,把当前结点加入list
res.add(root.val);
pre=root;
root=null;
}else {//说明此时右节点有元素,且未被添加
stack.push(root);
root=root.right;
}
}
return res;
}