确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
144.二叉树的前序遍历
145.二叉树的后序遍历
94.二叉树的中序遍历
给你二叉树的根节点 root
,返回它节点值的 前/中/后序 遍历。
前序遍历就是按照根节点,左节点,右节点的顺序遍历二叉树。
递归函数中首先判断当前节点是否为空,若为空则直接结束本次递归。
首先将根节点的值加入结果,然后对左节点调用递归,再对右节点调用递归,就可以实现前序遍历的规则。
class Solution {
public List preorderTraversal(TreeNode root) {
List ans=new ArrayList<>();
traversal(root,ans);
return ans;
}
public void traversal(TreeNode cur,List ans){
if(cur==null)
return;
ans.add(cur.val);
traversal(cur.left,ans);
traversal(cur.right,ans);
}
}
只要将递归函数中的代码顺序略作变换即可得到后序遍历
class Solution {
public List postorderTraversal(TreeNode root) {
List ans=new ArrayList<>();
traversal(root,ans);
return ans;
}
public void traversal(TreeNode cur,List ans){
if(cur==null)
return;
traversal(cur.left,ans);
traversal(cur.right,ans);
ans.add(cur.val);
}
}
同理
class Solution {
public List inorderTraversal(TreeNode root) {
List ans=new ArrayList<>();
traversal(root,ans);
return ans;
}
public void traversal(TreeNode cur,List ans){
if(cur==null)
return;
traversal(cur.left,ans);
ans.add(cur.val);
traversal(cur.right,ans);
}
}
首先把根节点压入栈中,然后直到栈中为空开始循环迭代,首先将栈中元素弹出(根节点前序),然后先压入右节点再压入左节点(这样才能够使整个的顺序是根左右)
class Solution {
public List preorderTraversal(TreeNode root) {
List ans=new ArrayList<>();
Stack stack=new Stack<>();
if(root==null)
return ans;
stack.push(root);
while(!stack.isEmpty()){
TreeNode node=stack.peek();
ans.add(stack.pop().val);
if(node.right!=null){
stack.push(node.right);
}
if(node.left!=null){
stack.push(node.left);
}
}
return ans;
}
}
迭代的解法不能像递归那样简单的修改一下代码就可以解出三道题。
中序遍历由于是左中右的顺序,所以首先应该向左遍历到底,到底之后加入答案并且从父节点开始向右儿子继续遍历
class Solution {
public List inorderTraversal(TreeNode root) {
List ans = new ArrayList<>();
Stack stack = new Stack<>();
if (root == null)
return ans;
TreeNode cur=new TreeNode();
cur=root;
while (!stack.isEmpty()||cur!=null) {
if(cur!=null){
stack.push(cur);
cur=cur.left;
} else{
cur= stack.peek();
stack.pop();
ans.add(cur.val);
cur=cur.right;
}
}
return ans;
}
}
后序遍历简单一点,左右中,而前序遍历是中左右,我们只要修改一下前序遍历就可以变成中右左,再倒序一下就变成了左右中。
class Solution {
public List postorderTraversal(TreeNode root) {
List ans=new ArrayList<>();
Stack stack=new Stack<>();
if(root==null)
return ans;
stack.push(root);
while(!stack.isEmpty()){
TreeNode node=stack.peek();
ans.add(stack.pop().val);
if(node.left!=null){
stack.push(node.left);
}
if(node.right!=null){
stack.push(node.right);
}
}
Collections.reverse(ans);
return ans;
}
}
这里反转ArrayList的方法是Collections.reverse。
递归法很好想,但是迭代法的思想还不太熟练,栈的运用不够熟练,中序遍历感觉有点像回溯法。