14-1.144二叉树的前序遍历
题目
思路
递归、迭代不统一、迭代统一
代码
//递归
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorder(root, res);
return res;
}
public void preorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
list.add(root.val);
preorder(root.left, list);
preorder(root.right, list);
}
}
//迭代风格不统一
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
res.add(node.val);
if (node.right != null) { //先放右孩子
stack.push(node.right);
}
if (node.left != null) { //再放左孩子
stack.push(node.left);
}
}
return res;
}
}
//迭代风格统一
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null) {
stack.push(root);
}
while (!stack.isEmpty()) {
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();
res.add(node.val); //加入到结果集中
}
}
return res;
}
}
14-2.94二叉树的中序遍历
题目
思路
递归、迭代不统一、迭代统一
代码
//递归
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
}
//迭代风格不统一
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur = cur.left;
}else {
cur = stack.pop();
res.add(cur.val);
cur = cur.right;
}
}
return res;
}
}
//迭代风格统一
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null) {
stack.push(root);
}
while (!stack.isEmpty()) {
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();
res.add(node.val); //加入到结果集中
}
}
return res;
}
}
X-3.145二叉树的后序遍历
题目
思路
递归、迭代不统一、迭代统一
代码
//递归
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList>();
postorder(root, res);
return res;
}
public void postorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
postorder(root.left, list);
postorder(root.right, list);
list.add(root.val);
}
}
//迭代风格不统一
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
res.add(node.val);
if (node.left != null) { //先放左孩子
stack.push(node.left);
}
if (node.right != null) { //再放右孩子
stack.push(node.right);
}
}
Collections.reverse(res); //根右左reverse为左右根
return res;
}
}
//迭代风格统一
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null) {
stack.push(root);
}
while (!stack.isEmpty()) {
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();
res.add(node.val); //加入到结果集中
}
}
return res;
}
}
二叉树的遍历总结
递归三要素
- 确定递归函数的参数和返回值
确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么,进而确定递归函数的返回类型 - 确定终止条件
写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出 - 确定单层递归的逻辑
确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程
迭代风格不统一的原因
中序与前序和后序的代码不同,是因为前序遍历中访问节点(遍历节点)和处理节点(将元素放进result数组中)可以同步处理,但是中序就无法做到同步
标记法
要处理的结点入栈后,紧接着放入一个空指针作为标记