二叉树的种类
- 满二叉树:只有度为0和度为2的节点,并且度为0的节点在同一层上的树称为满二叉树。树的高度为n,总节点树为2^n - 1。
- 完全二叉树:除了最底层的节点可能没填满以外,其余每层节点数都到达最大值,并且最下面一层的节点都记住在该层左边的若干位置。堆就是一个完全二叉树。
- 二叉搜索树(BST):二叉搜索树是有数值的,是一个有序树。如果左子树不为空,则左子树上所有节点的值均小于它根节点的值;如果右子树不为空,则右子树上所有节点的值大于根节点的值。
- 平衡二叉搜索树(AVL):是一颗空树或树它的左右两个子树的高度差不超过1,且左右两个子树都是一颗平衡二叉树。
二叉树的存储方式
- 链式存储:用左右指针存储子节点,通过指针把各个地址的节点串联到一起。
- 顺序存储:用数组来存储,在内存中是连续分布的。
二叉树的遍历方式
- 深度优先遍历(Depth-First Search, DFS):先往深走,如果遇到叶子节点再往回走。深度优先遍历分为三种,前中后序代表的是遍历中间节点的顺序,都从中间节点或是左边节点开始遍历,DFS遍历用递归法较为方便,并且可以借助栈的递归来实现。
- 前序遍历(递归,迭代):中 -> 左 -> 右
- 中序遍历(递归,迭代):左 -> 中 -> 右
- 后序遍历(递归,迭代):左 -> 右 -> 中
- 广度优先遍历(Breadth-First Search, BFS):一层一层遍历。一般用队列来实现广度优先遍历,因为我们需要先进先出的结构才能按层来遍历二叉树。
二叉树的定义(Java)
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;
}
}
二叉树的递归遍历
不论是前中后序遍历,在我们做题前先要掌握三个要素:
- 递归函数的参数和返回值
- 终止条件
- 单次递归的逻辑
以下三题是二叉树的前中后序遍历:
LeetCode - 144 Binary Tree Preorder Traversal
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> res) {
if (root == null) return; //终止条件
//中 -> 左 -> 右 遍历
res.add(root.val);
preorder(root.left, res);
preorder(root.right, res);
}
}
LeetCode - 94 Binary Tree Inorder Traversal
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> res) {
if (root == null) return;
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
}
LeetCode - 145 Binary Tree Postorder Traversal
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> res) {
if (root == null) return;
postorder(root.left, res);
postorder(root.right, res);
res.add(root.val);
}
}
1. 确认递归函数的参数和返回值:参数我们在传入递归函数时在传入root的基础上还要传入我们的结果集res,递归函数只负责在res中添加元素,因此不需要返回值;
2.确认终止条件:终止条件即为当当前的节点为空时则停止;
3.确认单层递归的逻辑:按照不同序的遍历逻辑来实现,但是中间节点也就是当前root节点的值始终是要加入结果集的,只不过加入的时机略有不同。