非递归法,也就是迭代法,其实是用stack栈数据机构来模拟递归方法的过程
对于比较简单的递归法,可以用栈来模拟,比如说二叉树的前中后序遍历就是必须先掌握的
题目一 前序遍历144. 二叉树的前序遍历 - 力扣(LeetCode)
思路
- 前序遍历是先处理中,再处理左,最后处理右
- 首先将根节点入栈,弹出根节点,处理节点
- 处理当前节点包括:(1)将节点值保存;(2)将其(非空)右节点入栈;(3)将其(非空)左节点入栈
- 当stack不为空,循环3,直到栈为空
代码
- 注意:特殊情况处理,当root节点为空时,返回空数组
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
ArrayList<Integer> result = new ArrayList<>();
if(root == null) {
return result;
}
stack.push(root);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
result.add(node.val);
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
}
return result;
}
}
题目二 中序遍历94. 二叉树的中序遍历 - 力扣(LeetCode)
递归法代码
- 将递归函数稍微调整位置即可
| 前序 | 中序 | 后序 |
|---|---|---|
preorder(node.left,result); | result.add(node.val); | postorder(node.left,result); |
result.add(node.val); | inorder(node.left,result); | postorder(node.right,result); |
preorder(node.right,result); | inorder(node.right,result); | result.add(node.val); |
// 递归法-中序
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
ArrayList<Integer> result = new ArrayList<>();
if(root == null) {
return result;
}
inorder(root,result);
return result;
}
public void inorder(TreeNode node, ArrayList<Integer> result) {
if(node == null) {
return;
}
inorder(node.left,result);
result.add(node.val);
inorder(node.right,result);
}
}
// 递归法-后序
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(root == null) {
return res;
}
postorder(root,res);
return res;
}
public void postorder(TreeNode node,ArrayList<Integer> res) {
if(node == null) {
return;
}
postorder(node.left,res);
postorder(node.right,res);
res.add(node.val);
}
}
思路
- 中序遍历,先处理左节点,再处理中节点,最后处理右节点
- 首先将根节点入栈,弹出根节点,处理节点
- 处理节点:(1)节点的(非空)右节点入栈;(2)节点入栈+null入栈;(3)节点的(非空)左节点入栈
- 弹出栈顶元素,重复3,直到遇到xxx
在3(2)节点入栈时应该在后面标记null,表示这个节点已经搜索过了
第4步,弹出栈顶元素,若遇到null,则把栈顶元素弹出记录res并continue;如果没有遇到null,说明该元素还没有访问过,重复3
代码
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
ArrayList<Integer> res = new ArrayList<>();
if(root == null) {
return res;
}
stack.push(root);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
if(node == null) {
res.add(stack.pop().val);
continue;
}
if(node.right != null) stack.push(node.right);
stack.push(node);
stack.push(null);
if(node.left != null) stack.push(node.left);
}
return res;
}
}
题目三 后序遍历145. 二叉树的后序遍历 - 力扣(LeetCode)
思路
- 后序遍历,先处理左节点,再处理右节点,最后处理中节点
- 首先将根节点入栈,弹出根节点,处理节点
- 处理节点:(1)节点入栈+null入栈;(2)节点的(非空)右节点入栈;(3)节点的(非空)左节点入栈
- 弹出栈顶元素,重复3,直到遇到xxx
在3(1)节点入栈时应该在后面标记null,表示这个节点已经搜索过了
弹出栈顶元素,若遇到null,把把栈顶元素弹出记录res并continue;如果没有遇到null,说明该元素还没有访问过,重复3
问题:
- 如果记录res后没有continue,有什么问题?此时继续往下执行,又把node入栈了,逻辑出大问题,所以,一定要记得退出continue当前循环,处理下一个弹出的元素
代码
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(root == null) {
return res;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
if(node == null) {
res.add(stack.pop().val);
continue;
}
stack.push(node);
stack.push(null);
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
}
return res;
}
}