leetcode 144 前序遍历
leetcode 94 中序遍历
leetcode 145 后序遍历
要求输出元素顺序
一、递归写法
1.1 前序遍历:根,左,右
思路:第一次访问结点,就要把结点放入结果序列,然后先访问左结点,再访问右结点,依次递归下去。
class Solution {
public void preOrder(TreeNode node,List<Integer> result){
if(node==null) return;//递归出口为访问到空结点
result.add(node.val);//第一次访问后立刻添加
preOrder(node.left,result);
preOrder(node.right,result);
}
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> x=new ArrayList();
preOrder(root,x);
return x;
}
}
1.2 中序遍历:左,根,右
思路:第二次访问结点(回溯时),把结点放入结果集合。
class Solution {
public void inOrder(TreeNode node,List<Integer> result){
if(node==null) return;
inOrder(node.left,result);//一直访问到最后一个左结点
result.add(node.val);//回溯时,将本结点加入结果序列
inOrder(node.right,result);//然后递归地访问右结点
}
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> x=new ArrayList<>();
inOrder(root,x);
return x;
}
}
1.3 后序遍历:左,右,根
思路:左右结点访问完,第三次访问根结点时,把结点加入到结果序列中。
class Solution {
public void postOrder(TreeNode node, List<Integer> result){
if(node==null) return;//访问到空结点返回
//递归访问左结点前,是对根结点的第一次访问
postOrder(node.left,result);
//访问完左子树,回溯,是对根结点的第二次访问
postOrder(node.right,result);
//访问完右子树,回溯,是对根结点的第三次访问,把本结点的值放入结果序列
result.add(node.val);
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> x=new ArrayList<>();
postOrder(root,x);
return x;
}
}
二、迭代法
递归法的原理是栈,先调用的会被放到栈底,回溯时最后被拿出调用,后调用的在栈顶,越靠近栈顶,回溯时越先被调用。
2.1 前序遍历(根,左,右)
思路:根结点进栈,根结点出栈,右结点进栈,左结点进栈,左结点出栈,右结点出栈
出栈顺序即为结果顺序
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> x=new ArrayList<>();
Stack<TreeNode> stack=new Stack();
if(root==null) return x;
stack.push(root);
while(!stack.empty()){
TreeNode temp=stack.pop();//根元素出栈
x.add(temp.val);//出栈的元素的值要放入结果序列中
/*
右结点先入栈,左结点后入栈,栈顶元素作为新的根结点在下次循环中先被弹出
直到栈为空。(所有元素都进栈一次,出栈一次,出栈顺序即结果顺序)
*/
if(temp.right!=null) stack.push(temp.right);
if(temp.left!=null) stack.push(temp.left);
}
return x;
}
2.2 后序遍历 (左,右,根)
后序遍历其实和前序遍历正好反着
思路:根进栈后,立刻出栈,先让左结点进,再让右结点进,然后右结点先出,左结点后 出。
这样出栈顺序就变为了 根右左
正好和我们想要的结果相反,
把结果序列反转即可得到正确答案。
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> x=new ArrayList<>();
Stack<TreeNode> stack=new Stack();
if(root==null) return x;
stack.push(root);
while(!stack.empty()){
TreeNode temp=stack.pop();//根元素出栈
x.add(temp.val);//出栈的元素的值要放入结果序列中
/*
左结点先入栈,右结点后入栈,栈顶元素作为新的根结点在下次循环中先被弹出
直到栈为空。(所有元素都进栈一次,出栈一次,出栈顺序反转即结果顺序)
*/
if(temp.left!=null) stack.push(temp.left);
if(temp.right!=null) stack.push(temp.right);
}
Collections.reverse(x);
return x;
}
2.3 中序遍历(左,根,右)
思路:前序遍历的核心在于访问的元素和要放入结果序列的元素是同一个,而中序遍历的难点是访问的元素和放入结果序列的元素不是同一个,要一直访问到左边底部的元素,才开始出栈,放入结果序列。
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> x=new ArrayList<>();
Stack<TreeNode> stack=new Stack();
if(root==null) return x;
TreeNode t=root;//t指向访问的元素,只有访问到左侧最底部的元素时才可以出栈
//结束循环的条件其实只有栈为空(t!=null时表示还有元素可以入栈)
while(t!=null||!stack.empty()){
if(t!=null){
stack.push(t);
t=t.left;
}else{
TreeNode temp=stack.pop();
x.add(temp.val);
t=temp.right;
}
}
return x;
}