前言
二叉树种类
- 满二叉树:每一层的节点个数都达到了最大值
- 完全二叉树:相比满二叉树来说,完全二叉树的最后一层的节点是从左到右连续的
- 二叉搜索树:对于任意一棵树的根节点来说,左边都比根节点小,右边都比根节点大
- 平衡二叉搜索树:在二叉搜索树的基础上,它的左子树的高度与右子树的高度的差值 <= 1
存储方式
- 链式存储:左右指针
- 顺序存储:比如堆(假如根节点为0下标,那么左孩子为2i+1,右孩子2i+2)
遍历方式
- 深度优先:前中后序遍历
- 广度优先:层序遍历
递归三部曲
- 确定递归函数的参数和返回值
- 确定终止条件
- 确定单层递归的逻辑
144. 二叉树的前序遍历
题目
思路
- 递归
- 迭代:借助栈
代码
// 递归
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) return list;
list.add(root.val);
List<Integer> ret = preorderTraversal(root.left);
list.addAll(ret);
ret = preorderTraversal(root.right);
list.addAll(ret);
return list;
}
// 迭代1
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
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;
}
// 迭代2
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) return list;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.empty()) {
while(cur != null) {
stack.push(cur);
list.add(cur.val);
cur = cur.left;
}
// 弹出栈顶,走右边
TreeNode top = stack.pop();
cur = top.right;
}
return list;
}
145. 二叉树的后序遍历
题目
思路
- 递归
- 迭代:借助栈
代码
// 递归
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) return list;
List<Integer> ret = postorderTraversal(root.left);
list.addAll(ret);
ret = postorderTraversal(root.right);
list.addAll(ret);
list.add(root.val);
return list;
}
// 迭代1
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root == null) return result;
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
result.add(node.val);
if(node.left != null) stack.push(node.left);
if(node.right != null) stack.push(node.right);
}
Collections.reverse(result);
return result;
}
// 迭代2
public List<Integer> postOrderTraversal(TreeNode3 root) {
if(root == null) return list;
List<Integer> list = new ArrayList<>();
Stack<TreeNode3> stack = new Stack<>();
TreeNode3 cur = root;
TreeNode3 prev = null; // 记录上一次打印的元素,防止死循环了
while(cur != null || !stack.empty()) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
// 不能弹出,继续走右边,右边为空才能弹出
TreeNode3 top = stack.peek();
if(top.right == null || prev == top) {
stack.pop();
list.add(top.val);
prev = top;
} else {
cur = top.right;
}
}
return list;
}
94. 二叉树的中序遍历
题目
思路
- 递归
- 迭代:借助栈
代码
// 递归
public void inorder(TreeNode root, List<Integer> ret) {
if(root == null) {
return;
}
inorder(root.left,ret);
ret.add(root.val);
inorder(root.right,ret);
}
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>();
inorder(root,ret);
return ret;
}
// 迭代2
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) return list;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.empty()) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
// 弹出栈顶,走右边
TreeNode top = stack.pop();
list.add(top.val);
cur = top.right;
}
return list;
}
注意点:
上述三种遍历操作中,对比:
前序和后序的迭代1方法;前序和中序的迭代2方法
102. 二叉树的层序遍历
题目
思路
迭代:借助队列
代码
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<>();
if(root == null) return ret;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int size = queue.size(); // 每一层的节点个数
List<Integer> list = new ArrayList<>();
while(size > 0) {
TreeNode cur = queue.poll();
list.add(cur.val);
size--;
if(cur.left != null) {
queue.offer(cur.left);
}
if(cur.right != null) {
queue.offer(cur.right);
}
}
ret.add(list);
}
return ret;
}