一、平衡二叉树
二、平衡二叉树的定义
- 二叉搜索树
对于一个二叉树的任意一个节点的,其左子树的所有节点的值都比它小,其右子树的所有的值都比它大。 - 平衡因子
一棵树的左子树的高度与右子树的高度的差值。 - 平衡二叉树
一个二叉搜索树,其任意一个子树的平衡因子不大于1。
三、平衡二叉树调整
- 添加节点
从添加的节点向其父节点搜索,知道找到一个节点的平衡因子大于1的节点。选择搜索路径中距离该节点最近的两个节点与这个节点构成三种类型的树:
选择这三个节点中值中等的节点作为父节点,其余节点作为其子节点。
<1>对于LL型,选择B作为父节点,C为左节点,A为右节点
<2>对于LR型,选择C作为父节点,B作为右子树节点,A作为左子树节点
<3>对于RL型,选择C作为父节点,A作为左子树节点,B作为右子树节点
<4>对于RR型,选择B作为父节点,A作为左子树节点,B作为右子树节点
二、红黑树
红黑树的基本属性
color,key,left,right,p。如果一个节点没有子节点或者父节点,则该节点指向NIL,其实也就是红黑树的叶节点的指针为null的节点,让其指向一个哨兵节点。处理NIL节点外,其余节点称为内部节点。
红黑树的定义
红黑树的性质
- 一个有n个内部节点的红黑树的高度最多为 2 l g ( n + 1 ) 2lg(n+1) 2lg(n+1)
- 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长(由红黑树的定义4和5可得到)
红黑树插入节点
对于插入节点,将其赋为红色,这样插入后不会改变每个节点到其页节点的简单路径上黑色节点的个数。
<1>插入的节点有叔叔节点并且为红色,将根节点颜色和页节点颜色互换,父节点就是根节点则将其设置为黑色。
<2>插入的节点没有叔叔节点或者不为红,利用平衡二叉树中的旋转方法,根节点设置为黑色,叶节点设置为红色(三个节点为祖孙三代)。
<3>使用<1>和<2>调整过后任然不满足红黑树的定义则需要递归进行上面的操作
<4>为什么父亲的兄弟为红色则反色,父亲兄弟不存在或者为黑色则旋转:
如果父亲兄弟为红色则父亲节点和兄弟节点都为红色,反色后并不会改变到叶节点的黑节点的个数,如果父亲父亲兄弟不存在或者为黑色直接反色会改变黑色节点数量。
<5>源代码
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
TreeNode<K,V> x) {
//插入节点设置为红色
x.red = true;
//xp:x的父节点,xpp:xp的父节点,xppl:xpp的左节点,xppr:xpp的右节点
for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
//父节点为空,说明插入的是头节点
if ((xp = x.parent) == null) {
x.red = false;
return x;
}
//父节点不为空,父节点为黑色不需要调整或者父节点为根节点,根节点一定为黑色也不需要调整
else if (!xp.red || (xpp = xp.parent) == null)
return root;
//父节点是左孩子节点
if (xp == (xppl = xpp.left)) {
//父节点的右兄弟节点不为空并且为红色,祖父节点设置为红色,父节点及兄弟设置为黑色
if ((xppr = xpp.right) != null && xppr.red) {
xppr.red = false;
xp.red = false;
xpp.red = true;
//将当前节点设置为祖父节点,继续向上调整
x = xpp;
}
//父亲节点的右节点不存在或者为黑色
else {
//当前节点在右边,则类似AVL树种的LR类型,先进行左旋
if (x == xp.right) {
root = rotateLeft(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateRight(root, xpp);
}
}
}
}
//父节点是右孩子节点
else {
//左兄弟不为空并且为红色,则反色
if (xppl != null && xppl.red) {
xppl.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
//为空或者为红色则旋转
else {
if (x == xp.left) {
root = rotateRight(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateLeft(root, xpp);
}
}
}
}
}
}
平衡二叉树删除节点
- 两种情况
(1)删除节点为叶子节点
(2)删除节点为非叶子节点
删除非叶子节点时可以将非叶子节点和其前驱或者后继节点交换(只交换节点的值不交换颜色),然后再删除(这就变成了第一种情况)。 - 删除叶子节点
(1)删除节点为红色:直接删除
(2)删除节点为黑色:删除节点的兄弟节点的黑高一定为1,只需要在删除节点的位置上填加一个子树让其黑高为1或者通过染色让其兄弟节点的黑高为0即可。详细参考:https://blog.csdn.net/qq_40843865/article/details/102498310
为什么有平衡二叉树还要红黑树
插入、删除节点时会频繁破坏平衡二叉树,需要进行旋转操作,而对于红黑树,插入删除节点时对红黑树的破坏比较小,并且有时红黑树不需要旋转操作,只需要改变节点颜色即可。
B树、B-树
B树和B-树指的是同一种树
B树的定义
<1>B树的节点结构
其中
P
i
P_i
Pi指向子节点,
K
i
K_i
Ki是关键字并且
K
i
<
K
i
+
1
K_i < K_{i+1}
Ki<Ki+1,
P
(
i
)
P_(i)
P(i)指向的子节点的键都比
K
i
−
1
K_{i-1}
Ki−1大并且比
K
i
+
1
K_{i+1}
Ki+1小。
<2>B树的定义
(1)树中每个结点至多有m棵子树;
(2)若根结点不是叶子结点,则至少有两棵子树;
(3)除根之外的所有非终端结点至少有「m/2]棵子树;
(4)所有的叶子结点都出现在同一层次上,并且不带信息,通常称为失败结点(失败结点并不存在,指向这些结点的指针为空。引入失败结点是为了便千分析B-树的查找性能);
(5)所有的非终端结点最多有m- 1个关键字,结点的结构如图所示。
B+树
节点数据存储在叶子节点上,非叶子节点不存放数据。