二叉树
1 树的分类
1.1 二叉树(✓)


- 树中一个节点的孩子节点的个数叫该节点的度,如A节点2度。
二叉树代码(✓)

- 一棵树必有一个根节点
- 二叉树:有且只有左右孩子
静态创建二叉树(✓)



- 遍历重点:递归
- 出口:节点为空,以上面树为例(前序遍历为例),此时递归到15节点,15不为空,进入if判断,查找他的孩子节点,进入递归,此时它没有孩子节点,所以getLeftChild返回值为null,传入preShowTreeNode(rootNode.getLeftChild()),preShowTreeNode(TreeNode rootNode)此时rootNode为null,if判断失败,退出递归。
package MyTree;
public class TreeNode {
private TreeNode leftChild;
private TreeNode rightChild;
private int value;
// 构造函数
public TreeNode(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
// setter 和 getter
public void setLeftChild(TreeNode tmp){
leftChild = tmp;
}
public void setRightChild(TreeNode tmp){
rightChild = tmp;
}
public TreeNode getLeftChild() {
return leftChild;
}
public TreeNode getRightChild() {
return rightChild;
}
// 前序遍历
public static void preShowTreeNode(TreeNode rootNode){
if (rootNode != null){
// 访问跟节点
System.out.println("先序---"+rootNode.getValue());
// 访问左孩子
preShowTreeNode(rootNode.getLeftChild());
// 访问右孩子
preShowTreeNode(rootNode.getRightChild());
}
}
// 中序遍历
public static void midShowTreeNode(TreeNode rootNode){
if (rootNode != null){
// 访问左孩子
midShowTreeNode(rootNode.getLeftChild());
// 访问跟节点
System.out.println("中序---"+rootNode.getValue());
// 访问右孩子
midShowTreeNode(rootNode.getRightChild());
}
}
// 后序遍历
public static void afterShowTreeNode(TreeNode rootNode){
if (rootNode != null){
// 访问左孩子
afterShowTreeNode(rootNode.getLeftChild());
// 访问右孩子
afterShowTreeNode(rootNode.getRightChild());
// 访问跟节点
System.out.println("后序---"+rootNode.getValue());
}
}
}
package MyTree;
public class TreeDemo01 {
public static void main(String[] args) {
TreeNode t1 = new TreeNode(10);
TreeNode t2 = new TreeNode(9);
TreeNode t3 = new TreeNode(20);
TreeNode t4 = new TreeNode(15);
TreeNode t5 = new TreeNode(35);
t1.setLeftChild(t2);
t1.setRightChild(t3);
t3.setLeftChild(t4);
t3.setRightChild(t5);
TreeNode.preShowTreeNode(t1);
TreeNode.midShowTreeNode(t1);
TreeNode.afterShowTreeNode(t1);
}
}

动态创建二叉树(✓)







1.1.1 满二叉树(✓)
- 如果一棵二叉树的结点要么是叶子结点,要么它有两个子结点,这样的树就是满二叉树。
- 高度为h,由2^h-1个节点构成的二叉树称为满二叉树。

1.1.2 完全二叉树(✓)
-
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。(百度百科)
-
完全二叉树是由满二叉树而引出来的,若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数(即1~h-1层为一个满二叉树,h层只有叶子节点),第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
-
堆一般都是用完全二叉树来实现的。

1.1.3 完满二叉树(✓)
- 所有非叶子结点的度都是2。(只要你有孩子,你就必然是有两个孩子)

1.2 二叉查找树(Binary Search Tree,BST,二叉搜索树,二叉排序树)(✓)
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的结点。

1.3 平衡二叉树(Balanced Binary Tree)(✓)
- 任意节点的子树的高度差都小于等于1

1.3.1 为什么要有平衡二叉树(✓)
-
二叉搜索树一定程度上可以提高搜索效率,但是当原序列有序时,例如序列 A = {1,2,3,4,5,6},构造二叉搜索树如图。依据此序列构造的二叉搜索树为右斜树,同时二叉树退化成单链表,搜索效率降低为 O(n)。

-
在此二叉搜索树中查找元素 6 需要查找 6 次。
-
二叉搜索树的查找效率取决于树的高度,因此保持树的高度最小,即可保证树的查找效率。同样的序列 A,将其改为图 1.2 的方式存储,查找元素 6 时只需比较 3 次,查找效率提升一倍。

-
可以看出当节点数目一定,保持树的左右两端保持平衡,树的查找效率最高。
-
这种左右子树的高度相差不超过 1 的树为平衡二叉树。
1.3.2 AVL树(自平衡二叉查找树)(✓)
-
AVL树本质上还是一棵二叉搜索树,它的特点是:
- 本身首先是一棵二叉搜索树。
- 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
- 也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。
1.3.3 红黑树(✓)
- 参考
- 红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。
- 红黑树使用红黑二色进行“着色”,目的是利用颜色值作为二叉树的平衡对称性的检查,只要插入的节点“着色”满足红黑二色的规定,最短路径与最长路径不会相差的太远,红黑树的节点分布就能大体上达至均衡。
1.4 B树(✓)
-
B 树相当于是一棵多叉查找树
-
子节点数:非叶节点的子节点数>1,且<=M ,且M>=2,空树除外(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2则是2叉树,M=3则是3叉);
-
B树比BST在磁盘操作的次数上更少(空间局部性)
-
适用于文件系统

-
图中是一棵m = 3 的 3 阶 B 树,可以看出,树中有些节点是有多个元素的,并且和二叉查找树一样,左节点的所有元素的值都比父亲元素小。例如对于(3, 7)这个节点。两个元素把这个节点分割成三个值域,即可以有 3 个孩子。2 相当于 3 的左孩子节点,而 (4,6)相当于 3 的右孩子,同时也是 7 的左孩子,而 9 是 7 的右孩子。
-
和二叉查找树还是很相似滴,都是有序,且左孩子小,右孩子大,只是 B 树的一个节点可以有多个元素,并且有多个分支。而这些分支以及元素的数量规则,可以从上面的五个规则中查找哈。说实话,我也懒的记那些规则,只知道个大概以及 B 树的应用即可。
1.4.1 B+树(✓)
- 参考
- B+树是升级版B树,数据都在叶子节点,叶子节点之间加了指针形成链表。
- 适用于数据库索引,查询时候可能查询很多条,这样就不用跨层访问(链表)
- hash比B+快,为啥数据库不用hash?
- 这和业务场景有关。如果只选一个数据,那确实是hash更快。但是数据库中经常会选择多条,这时候由于B+树索引有序,并且又有链表相连,它的查询效率比hash就快很多了。
- 而且数据库中的索引一般是在磁盘上,数据量大的情况可能无法一次装入内存,B+树的设计可以允许数据分批加载,同时树的高度较低,提高查找效率。
1.4.2 B*树(暂留)
1.5 线索二叉树(暂留)
1.6 最优二叉树(霍夫曼树,哈夫曼树)(✓)
- 带权路径长度WPL最小的二叉树,权值较大的结点离根较近
- 把查询比率越大的放在上层,这样查询的时候就不用一直向下查询,时间短。


被折叠的 条评论
为什么被折叠?



