文章讲解
- 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
- 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
- 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
//前序递归
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorder(root,res);
return res;
}
public void preorder(TreeNode node, List<Integer> res){
if(node == null){
return ;
}
res.add(node.val);
preorder(node.left,res);
preorder(node.right,res);
}
}
//后序递归
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(root,res);
return res;
}
public void postorder(TreeNode node, List<Integer> res){
if(node == null){
return ;
}
postorder(node.left,res);
postorder(node.right,res);
res.add(node.val);
}
}
//中序递归
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root,res);
return res;
}
public void inorder(TreeNode node, List<Integer> res){
if(node == null){
return ;
}
inorder(node.left,res);
res.add(node.val);
inorder(node.right,res);
}
}
文章讲解
//前序迭代:中 左 右
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
//根节点入栈
stack.push(root);
//循环处理栈 中 左 右
while(!stack.isEmpty()){
//弹出栈顶元素
TreeNode node = stack.pop();
if(node != null){
result.add(node.val);
}else continue;
//先放入右孩子
stack.add(node.right);
//再放入左孩子
stack.add(node.left);
}
return result;
}
}
//后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
//根节点入栈
stack.push(root);
//循环处理栈 中 右 左
while(!stack.isEmpty()){
//弹出栈顶元素
TreeNode node = stack.pop();
if(node != null){
result.add(node.val);
}else continue;
//先放入左孩子
stack.add(node.left);
//再放入右孩子
stack.add(node.right);
}
//翻转 :中 右 左 -> 左 右 中
Collections.reverse(result);
return result;
}
}
//中序遍历
//中序遍历无法使用以上逻辑:处理节点和遍历节点不同
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){
//cur不为空,把已经遍历过的元素存入栈中,遍历左孩子
if(cur != null){
stack.push(cur);
cur = cur.left;
//cur为空,处理栈顶元素,遍历右孩子
}else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}
将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。
标记方法:要处理的节点放入栈之后,紧接着放入一个空指针作为标记。
文章讲解
//前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null) stack.push(root);
while (!stack.empty()) {
TreeNode node = stack.peek();
if (node != null) {
// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
stack.pop();
// 添加右节点(空节点不入栈)
if (node.right!=null) stack.push(node.right);
// 添加左节点(空节点不入栈)
if (node.left!=null) stack.push(node.left);
// 添加中节点
stack.push(node);
// 中节点访问过,但是还没有处理,加入空节点做为标记。
stack.push(null);
// 只有遇到空节点的时候,才将下一个节点放进结果集
} else {
// 将空节点弹出
stack.pop();
// 重新取出栈中元素
node = stack.peek();
stack.pop();
// 加入到结果集
result.add(node.val);
}
}
return result;
}
}
//中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null) stack.push(root);
while (!stack.empty()) {
TreeNode node = stack.peek();
if (node != null) {
// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
stack.pop();
// 添加右节点(空节点不入栈)
if (node.right!=null) stack.push(node.right);
// 添加中节点
stack.push(node);
// 中节点访问过,但是还没有处理,加入空节点做为标记。
stack.push(null);
// 添加左节点(空节点不入栈)
if (node.left!=null) stack.push(node.left);
// 只有遇到空节点的时候,才将下一个节点放进结果集
} else {
// 将空节点弹出
stack.pop();
// 重新取出栈中元素
node = stack.peek();
stack.pop();
// 加入到结果集
result.add(node.val);
}
}
return result;
}
}
//后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null) stack.push(root);
while (!stack.empty()) {
TreeNode node = stack.peek();
if (node != null) {
// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
stack.pop();
// 添加中节点
stack.push(node);
// 中节点访问过,但是还没有处理,加入空节点做为标记。
stack.push(null);
// 添加右节点(空节点不入栈)
if (node.right!=null) stack.push(node.right);
// 添加左节点(空节点不入栈)
if (node.left!=null) stack.push(node.left);
// 只有遇到空节点的时候,才将下一个节点放进结果集
} else {
// 将空节点弹出
stack.pop();
// 重新取出栈中元素
node = stack.peek();
stack.pop();
// 加入到结果集
result.add(node.val);
}
}
return result;
}
}