(一)二叉树的前序遍历
题目描述:给定一个二叉树,返回它的 前序 遍历(根左右)。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,2,3]
解题思路:
从二叉树根结点开始,沿左子树一直走到末端(左孩子为空)为止,在走的过程中,访问所遇结点,并依次把所遇结点进栈,当左子树为空时,从栈顶退出某结点,并将指针指向该结点的右孩子。如此重复,直到栈为空或指针为空为止。
代码实现:
//方法一:递归,根左右
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
preorderTraversal(root,res);
return res;
}
public void preorderTraversal(TreeNode root,List<Integer> res){
if(root==null)
return ;
res.add(root.val);
preorderTraversal(root.left,res);
preorderTraversal(root.right,res);
}
}
//方法二:非递归方法
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null)
return res;
Stack<TreeNode> stack=new Stack<>();
TreeNode p=root;
while(p!=null || !stack.isEmpty()){
while(p!=null){
res.add(p.val);
stack.push(p); //进栈
p=p.left; //进入左子树
}
p=stack.pop(); //退栈
p=p.right;
}
return res;
}
}
(二)二叉树的中序遍历
题目:94. 二叉树的中序遍历
题目描述:给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,3,2]
解题思路:
从二叉树根结点开始,沿左子树一直走到末端(左孩子为空)为止,在走的过程中,把依次遇到的结点进栈,待左子树为空时,从栈中退出结点并访问,并将指针指向该结点的右孩子。如此重复,直到栈为空或指针为空为止。
代码实现:
//方法一:递归,左根右
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorderTraversal(root,res);
return res;
}
public void inorderTraversal(TreeNode root,List<Integer> res){
if(root==null)
return ;
inorderTraversal(root.left,res);
res.add(root.val);
inorderTraversal(root.right,res);
}
}
//方法二:非递归,迭代
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null)
return res;
Stack<TreeNode> stack=new Stack<>();
TreeNode p=root;
while(p!=null || !stack.isEmpty()){
while(p!=null){
stack.push(p); //进栈
p=p.left; //向左
}
p=stack.pop(); //弹栈
res.add(p.val); //访问
p=p.right; //向右
}
return res;
}
}
(三)二叉树的后序遍历
题目描述:给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [3,2,1]
解题思路:
在后序遍历中,当搜索指针指向某一个结点时,不能马上进行访问,而先要遍历左子树,所以此结点应先进栈保存,当遍历完它的左子树后,再次回到该结点,还不能访问它,还需先遍历其右子树,所以该结点还必须再次进栈,只有等它的右子树遍历完后,再次退栈时,才能访问该结点。为了区分同一结点的两次进栈,引入一个栈次数的标志,一个元素第一次进栈标志为0,第二次进栈标志为1,并将标志存入另一个栈中,当从标志栈中退出的元素为1时,访问结点。
代码实现:
//方法一:递归,左右根
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null)
return res;
postorderTraversal(root,res);
return res;
}
public void postorderTraversal(TreeNode root,List<Integer> res){
if(root==null)
return;
postorderTraversal(root.left,res);
postorderTraversal(root.right,res);
res.add(root.val);
}
}
//方法二:非递归
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null)
return res;
Stack<TreeNode> stack1=new Stack<>(); //栈1存放结点
Stack<Integer> stack2=new Stack<>(); //栈2存放进栈次数的标志
TreeNode p=root;
do{
while(p!=null){
stack1.push(p);
stack2.push(0);
p=p.left;
}
if(!stack1.isEmpty()){
int num=stack2.pop();
p=stack1.pop();
if(num==0){
stack1.push(p);
stack2.push(1);
p=p.right;
}
else{
res.add(p.val);
p=null;
}
}
}while(!stack1.isEmpty());
return res;
}
}
总结:
二叉树的深度优先遍历是二叉树题目中最基本的算法,很多算法都基于深度优先遍历进行变形,其中递归解法相对很简单,特别是对非递归的迭代方法,基于栈是基础,要着重理解。