二叉树相关
关于二叉树的概念
这里允许我简单搬运一下百度百科的定义
二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。
另外提几点:
a) full binary tree 每个节点都有0或2个子节点;complete binary tree 每一层都是从左铺到右的(不一定满)
b) 数据储存常用数组或者链表
下面讲一下他的四种遍历方式:
先来一个二叉树的栗子
前序遍历 Preorder
遍历顺序是 根-左-右 (具体流程可以参考下面伪代码),上图输出顺序为 17,33,19,16,38,31,48,11,14。
Function PreorderTraverse(T):
if T is non-empty then
visit T_root
PreorderTraverse(T_left)
PreorderTraverse(T_right)
我们可以用栈stack来实现前序遍历,伪代码如下
push(T)
while the stack is non-empty do
T <- pop
visit T_root
# 右节点先入后出
if T_right is non-empty then
push(T_right)
if T_left is non-empty then
push(T_left)
中序遍历 Inorder
遍历顺序 左-根-右 (同样的参考伪代码),上图中应输出为 19,33,38,16,31,17,11,48,14。
Function InorderTraverse(T):
if T is non-empty then
InorderTraverse(T_left)
visit T_root
InorderTraverse(T_right)
后序遍历 Postorder
遍历顺序 左-右-根 (参考伪代码),栗子中应输出 19,38,31,16,33,11,14,48,17。
Function PostorderTraverse(T):
if T is non-empty then
PostorderTraverse(T_left)
PostorderTraverse(T_right)
visit T_root
中序和后序遍历同样的也可以用stack实现,这里不再赘述。
层序遍历 level-order
层次遍历就是按照树的层次自上而下的遍历二叉树,图中顺序应为 17,33,48,19,16,11,14,38,31。
实现层序遍历可以用到队列queue,伪代码如下
inject(T)
while the queue is non-empty do
T <- eject
visit T_root
if T_left is non-empty then
inject(T_left)
if T_right is non-empty then
inject(T_right)
注意考点
已知前序遍历序列和中序遍历序列,确定一棵二叉树第一个就是根节点;
已知后序遍历序列和中序遍历序列,确定一棵二叉树最后一个是根节点;
已知前序遍历序列和后序遍历序列,不可以唯一确定一棵二叉树。
平衡树们
1、AVL树
AVL树是一种经典的平衡二叉树,它具有以下性质:它是一 棵空树或它的左右两个子树的高度差(左支高度-右支高度)的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。下面看几个例子,猜猜哪些是AVL树哪些不是?
公布答案,12是AVL平衡的,34不是。那么如何构建AVL树呢?这就有点复杂了,从空树开始构建过程中,我们每次加入一个新的节点都要check是否平衡,如果不平衡就要进行以下操作:
i) R-rotation
ii) L-rotation
iii) LR-rotation
iv) RL-rotation
旋转的时候要遵循从最低高度的子树开始,另外,对AVL树的删除操作比插入要难一些。
2、2-3树
前面提到AVL树在插入一个节点和删除一个节点都有可能调整多个节点的不平衡状态。频繁的左旋转和右旋转操作一定会影响整个AVL树的性能,除非是平衡与不平衡变化很少的情况下,否则AVL树所带来的搜索性能提升不足以弥补平衡树所带来的性能损耗。
2-3树,甚至2-3-4树是一类可用于搜索的树,他的节点可以存贮多个值,下图展示了2-树和3-树的概念。
我们再通过一个例子来学习一下2-3树的构建,假设有数组 [9,5,8,3,2,4,7],过程如下
3、红黑树
红黑树是一种特定类型的二叉树,它是在计算机科学中用来组织数据比如数字的块的一种结构。若一棵二叉查找树是红黑树,则它的任一子树必为红黑树. 红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但 对之进行平衡的代价较低, 其平均统计性能要强于 AVL。它满足以下性质:
性质1. 结点是红色或黑色。
性质2. 根结点是黑色。
性质3. 所有叶子都是黑色。(叶子是NIL结点)
性质4. 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
性质5. 从任一节结点其每个叶子的所有路径都包含相同数目的黑色结点。
4、B-树
前面讲的2-3树其实是最简单的一类B树。B-树可以理解为一种多路查找树,我们来看一个例子来了解他的性质,
如果现在我们要插入20和0,该怎么做?
这个网站可以演示B-tree的插入过程 https://www.cs.usfca.edu/~galles/visualization/BTree.html。
5、B+树
B+ 树是一种树数据结构,通常用于数据库和操作系统的文件系统中。B+ 树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+ 树元素自底向上插入,这与二叉树恰好相反。B+树满足以下的要求:
1)B+树包含2种类型的结点:内部结点(也称索引结点)和叶子结点。根结点本身即可以是内部结点,也可以是叶子结点。根结点的关键字个数最少可以只有1个。
2)B+树与B树最大的不同是内部结点不保存数据,只用于索引,所有数据(或者说记录)都保存在叶子结点中。
3) m阶B+树表示了内部结点最多有m-1个关键字(或者说内部结点最多有m个子树),阶数m同时限制了叶子结点最多存储m-1个记录。
4)内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它。叶子结点中的记录也按照key的大小排列。
5)每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序链接。