今天开始二叉树。
理论基础
看卡哥视频关于二叉树,你该了解这些!| 二叉树理论基础一网打尽以及代码随想录二叉树章节代码随想录--二叉树理论基础。
二叉树种类
(图见上面链接和自己笔记)
满二叉树
节点数:2^k-1 (k为二叉树的深度)
完全二叉树
完全二叉树:除了底层以外,其他层都是满的。底层是从左到右连续的。
可以发现,满二叉树一定是完全二叉树。
二叉搜索树
节点上的元素有一定顺序(左小右大),但节点的布局无要求。
平衡二叉搜索树
元素按一定顺序 (有序)。
左子树和右子树高度差的绝对值不能大于1。
map、set、multimap、multi set的底层实现都是平衡二叉搜索树,所以是有序的?它们在插入节点时都是log n级别,查询也都是log n级别。
map、set是无序的,这个有序和无序是根据有没有按照元素添加顺序排序。所以可以这样理解这个无序。参照:java map是有序的吗_java中map、set、list是否有序
map,set的底层是红黑树,红黑树即是平衡二叉树。Java集合:浅谈 Map集合的原理,底层以及使用
二叉树的存储方式
(图见上面链接和自己笔记)
链型存储
链表:左指针,右指针
线型存储
数组
对于第i个元素:
左孩子:2 * i + 1
右孩子:2 * i + 2
二叉树的遍历
深度优先搜索(递归/迭代)
前序遍历(中左右)
中序遍历(左中右)
后序遍历(左右中)
注:这里的“左”指左子树,“右”指右子树。
前序“中”在前,中序“中”在中,后序“中”在右。
广度优先搜索(迭代)
层序遍历:一层一层去遍历(迭代法)(队列)
二叉树的定义
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;
}
}
二叉树-递归遍历
递归三步曲
确定递归函数的参数和返回值
确定终止条件
确定单层递归的逻辑
前序遍历: 144.二叉树的前序遍历
递归方法的参数(需要时随时添)通常为:根节点,数组(存放遍历结果)。
递归方法的返回值:一般为void。
/**
* 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) {
//将结果存在ArrayList(数组)中。
List<Integer> result = new ArrayList<Integer>();
preorder(root, result);
return result;
}
/**递归方法 */
public void preorder(TreeNode root, List<Integer> result){
/**确定终止条件 */
if(root == null){
return;
}
/**确定单层递归的逻辑 */
result.add(root.val); //中
preorder(root.left, result); //左
preorder(root.right, result); //右
}
}
第19行,通过实现了List接口的ArrayList类进行实例化。关于List接口和ArrayList详见java中的List简单介绍。可以发现ArrayList可以看作一个可以改变大小的数组。与LinkedList(链表的特性)相比,ArrayList更适合检索(数组的特性)。因此这里通过ArrayList类进行实例化。
递归方法:参数(根节点root,存放遍历结果的数组result)
/**递归方法 */
public void preorder(TreeNode root, List<Integer> result){
确定终止条件:当根节点为null时,往上“归”。
/**确定终止条件 */
if(root == null){
return;
}
确定单层递归的逻辑:前序(中左右)
/**确定单层递归的逻辑 */
result.add(root.val); //中
preorder(root.left, result); //左
preorder(root.right, result); //右
中序遍历:94.二叉树的中序遍历
与前序基本一致,只是单层递归的逻辑为“左中右”而已。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
inorder(root, result);
return result;
}
public void inorder(TreeNode root, List<Integer> result){
//递归终止条件
if(root == null){
return;
}
inorder(root.left, result); //左
result.add(root.val); //中
inorder(root.right, result); //右
}
}
后序遍历:145.二叉树的后序遍历
与前序基本一致,只是单层递归的逻辑为“左右中”而已。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
postorder(root, result);
return result;
}
public void postorder(TreeNode root, List<Integer> result){
// 两参数:根节点root,result存储遍历结果
//判断递归终止条件
if(root == null){
return;
}
postorder(root.left, result); //左
postorder(root.right, result); //右
result.add(root.val); //中
}
}
后续学习
迭代遍历
题目链接/文章讲解/视频讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E8%BF%AD%E4%BB%A3%E9%81%8D%E5%8E%86.html
统一迭代
这是统一迭代法的写法, 如果学有余力,可以掌握一下