大师兄的数据结构学习笔记(十一): B树
大师兄的数据结构学习笔记(十三): KD树
一、关于红黑树
1. 比较两种平衡二叉树的优劣
类型 | 优点 | 缺点 |
---|---|---|
伸展树 | - 实现简便 - 无需修改结点结构 - 分摊复杂度低 |
最坏情况下单次操作耗时 |
AVL树 | 最坏情况下单次操作速度 | - 需要在结点中嵌入平衡因子等标识 - 删除操作之后的重平衡可能需要做多达次旋转 |
- 红黑树针对AVL树的不足进行了改进,通过指定结点颜色,并巧妙地动态调整,可保证在每次插入或删除操作之后的重新平衡过程中,全树拓扑结构的更新涉及常数个结点。
2. 关于红黑树
- 红黑树(Red Black Tree)是红、黑两色节点组成的二叉搜索树,且满足以下条件:
1) 树根始终为黑色。
2) 外部节点均为黑色。
3) 其余节点若为红色,则其孩子结点必为黑色。
4) 从任一外部节点到根节点的沿途,黑结点的数目相等。
- 根据以上条件,可以获得一些隐含的条件:
1) 红节点均为内部节点,且其父、左、右孩子节点必然存在。
2) 红节点之父节点必为黑色, 因此不存在相邻的红节点。
3) 从根节点通往任一节点,黑节点不少于红节点。
4) 所有外部节点的黑深度统一。
- 从根节点到任一节点,沿途所经黑节点的总数成为该节点的黑深度(black depth),根节点的深度为0。
- 从任一节点通往其任一后代外部节点的沿途,出去外部节点,途径的黑色节点总数称为该节点的黑高度(black height), 外部节点的黑高度为0。
3. 红黑树与B树
- 如果将一颗红黑树自顶而下逐层转换。
- 每遇到一个红节点,都将对应的子树整体提升一层,与父节点水平对齐,并将二者之间的联边相应调整为横向。
- 则可以转换为B树。
4. 红黑树的平衡性
- 红黑树不能如完全二叉树那样做到立项平衡。
- 也不如AVL树那样做到较严格的适度平衡。
- 但其高度扔控制在最小高的两倍以内,即:。
二、红黑树的调整
- 当插入或删除结点时,红黑树的规则有可能被打破,这时就需要通过变色或旋转来维持规则。
1. 旋转
- 红黑树的旋转规则可参考二叉搜索树。
2. 变色
- 在红黑树调整时,为了重新符合红黑树的规则,会尝试把红色节点变为黑色,或者把黑色节点变为红色。
2.1 双红修正
- 由于插入新节点,导致父子节点同为红色的情况,称为双红(double red)。
- 情况一: 叔父节点为黑色
1) 将x的父亲与祖父分别记作p和g。既然此前的红黑树合法,故作为红节点p的父亲,g必然存在且为黑色。
2) g作为内部节点,其另一孩子(即p的兄弟、x的叔父)也必然存在,将其记作u。
3) 将黑节点g调整到中间重构即可。
- 情况二: 叔父节点为红色
1) 在这种情况下,需要将相邻的结点染色,以满足红黑树规则。
template<class T>
void RBTree<T>::insertFixUp(RBTNode<T>*& root, RBTNode<T>* node)
{
RBTNode<T>* parent, * gparent;
// 若父节点存在,并且父节点的颜色是红色
while ((parent = node->parent) && parent->color==RED)
{
gparent = parent->parent;
if (parent == gparent -> lc) // 若父节点是祖父结点的左孩子
{
//如果叔叔节点是红色
RBTNode<T>* uncle = gparent->rc;
if (uncle && uncle->color == RED)
{
uncle->color = BLACK; // 改变颜色
parent->color = BLACK;
gparent->color = RED;
node = gparent;
continue;
}
//若叔叔节点是黑色,并且当前节点是右孩子
if (parent->rc == node)
{
RBTNode<T>* tmp;
leftRotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
//若叔叔节点是黑色,并且当前节点是左孩子
parent->color = BLACK;
gparent->color = RED;
rightRotate(root, gparent);
}
else //若父节点是祖父结点的右孩子
{
// 如果叔叔节点是红色
RBTNode<T>* uncle = gparent->lc;
if (uncle && uncle->color == RED)
{
uncle->color = BLACK;
parent->color = BLACK;
gparent->color = RED;
node = gparent;
continue;
}
// 如果叔叔是黑色,并且当前节点是左孩子
if (parent->lc == node)
{
RBTNode<T>* tmp;
rightRotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
// 如果叔叔是黑色,且当前节点是右孩子
parent->color = BLACK;
gparent->color = RED;
leftRotate(root, gparent);
}
}
root->color = BLACK; // 根节点设为黑色
}
2.2 双黑修正
- 在删除节点时,如果由于被删除节点和替换节点同为黑色,导致红黑树的黑高度不同的情况,称为双黑(double black)。
- 情况一: 待删除结点的兄弟结点为黑色,且至少有一个红孩子
1) 通过关键码的旋转消除超级节点的下溢。
- 情况二b: 待删除结点的兄弟结点为黑色,且两个孩子均为黑,父节点为黑
1) 兄弟结点转红
- 情况二r: 待删除结点的兄弟结点为黑色,且两个孩子均为黑,父节点为红
1) 兄弟结点转红。
- 情况三: 兄弟结点为红
1) zap(p)或zig(p)
2) 红s转黑,黑p转红
template<class T>
void RBTree<T>::removeFixUp(RBTNode<T>*& root, RBTNode<T>* node, RBTNode<T>* parent)
{
RBTNode<T>* other;//node的兄弟节点
while ((!node || node->color == BLACK) && node != root) //node为非根节点、为空或为黑色节点
{
if (parent->lc == node) //如果是左孩子
{
other = parent->rc;
if (other->color == RED) // 如果兄弟为红
{
other->color = BLACK;
parent->color = RED;
leftRotate(root, parent);
other = parent->rc;
}
if ((!other->lc || other->lc->color == BLACK) && (!other->rc || other->rc->color == BLACK))
{
//如果兄弟和兄弟的孩子节点都是黑
other->color = RED;
node = parent;
parent = node->parent;
}
else
{
if (!other->rc || other->rc->color == BLACK)
{
//如果兄弟的右孩子是黑色
other->lc->color = BLACK;
other->color = RED;
rightRotate(root, other);
other = parent->rc;
}
//如果右孩子是红色的
other->color = parent->color;
parent->color = BLACK;
other->lc->color = BLACK;
rightRotate(root, parent);
node = root;
break;
}
}
}
if (node)
{
node->color = BLACK;
}
}
三、实现红黑树
1. 节点结构
#ifndef _REDBLACKTREE_H_
#define _REDBLACKTREE_H_
#include <iostream>
#include <iomanip>
using namespace std;
enum RBTColor{RED,BLACK};
template<class T>
class RBTNode
{
public:
RBTColor color; //红黑色
T key; //键值
RBTNode* lc; //左子树
RBTNode* rc; //右子树
RBTNode* parent; //父节点
RBTNode(T value, RBTColor c,RBTNode*p,RBTNode *l,RBTNode *r):
key(value), color(c),parent(),lc(l),rc(r){}
};
2. 树结构
template<class T>
class RBTree {
public:
RBTree() :_root(nullptr) { _root = nullptr; }; //构造函数
~RBTree() { destroy(); }; //析构函数
void preOrder(); //前序遍历
void inOrder(); //中序遍历
void postOrder(); //后序遍历
RBTNode<T>* search(T key); //查找节点
T minimum(); //最小值
T maximum(); //最大值
RBTNode<T>* successor(RBTNode<T>* x); //找数值大于x的最小结点
RBTNode<T>* predecessor(RBTNode<T>* x); //找数值小于x的最大结点
void insert(T key); //插入结点
void remove(T key); //删除结点
void destroy(); //销毁红黑树
void print(); //打印结点
private:
void preOrder(RBTNode<T>* tree) const; //先序遍历
void inOrder(RBTNode<T>* tree) const; //中序遍历
void postOrder(RBTNode<T>* tree) const; //后序遍历
RBTNode<T>* search(RBTNode<T>* x, T key) const; //查找节点
RBTNode<T>* minimum(RBTNode<T>* tree); //最小节点
RBTNode<T>* maximum(RBTNode<T>* tree); //最大节点
void leftRotate(RBTNode<T>*& root, RBTNode<T>* x); //左旋
void rightRotate(RBTNode<T>*& root, RBTNode<T>* x); //右旋
void insert(RBTNode<T>*& root, RBTNode<T>* node); //插入函数
void insertFixUp(RBTNode<T>*& root, RBTNode<T>* node); //插入修正函数
void remove(RBTNode<T>*& root, RBTNode<T>* node); //删除函数
void removeFixUp(RBTNode<T>*& root, RBTNode<T>* node, RBTNode<T>* parent); //删除修正函数
void destroy(RBTNode<T>*& tree);
void print(RBTNode<T>* tree, T key, int direction);
private:
RBTNode<T>* _root; //根节点
};
3. 方法实现
template<class T>
// 先序遍历
void RBTree<T>::preOrder(RBTNode<T>* tree) const
{
if (tree)
{
cout << tree->key << endl;
preOrder(tree->lc);
preOrder(tree->rc);
}
}
template<class T>
// 先序遍历
void RBTree<T>::preOrder()
{
preOrder(_root);
}
template<class T>
// 中序遍历
void RBTree<T>::inOrder(RBTNode<T>* tree) const
{
if (tree)
{
preOrder(tree->lc);
cout << tree->key << endl;
preOrder(tree->rc);
}
}
template<class T>
// 中序遍历
void RBTree<T>::inOrder()
{
inOrder(_root);
}
template<class T>
// 后序遍历
void RBTree<T>::postOrder(RBTNode<T>* tree) const
{
if (tree)
{
preOrder(tree->lc);
preOrder(tree->rc);
cout << tree->key << endl;
}
}
template<class T>
// 后序遍历
void RBTree<T>::postOrder()
{
postOrder(_root);
}
template<class T>
//查找节点
RBTNode<T>* RBTree<T>::search(RBTNode<T>* x, T key) const
{
if (x == nullptr || x->key == key)
{
return x;
}
if (key < x->key)
{
return search(x->lc,key);
}
else
{
return search(x->rc, key);
}
}
template<class T>
//查找节点
RBTNode<T>* RBTree<T>::search(T key)
{
serch(_root, key);
}
template<class T>
//最小节点
RBTNode<T>* RBTree<T>::minimum(RBTNode<T>* tree)
{
if (!tree) {
return nullptr;
}
while (tree->lc)
{
tree = tree->lc;
}
return tree;
}
template<class T>
//最小节点
T RBTree<T>::minimum()
{
RBTNode<T>* p = minimum(_root);
if (p)
{
return p->key;
}
return (T)nullptr;
}
template<class T>
//最大节点
RBTNode<T>* RBTree<T>::maximum(RBTNode<T>* tree)
{
if (!tree) {
return nullptr;
}
while (tree->rc)
{
tree = tree->rc;
}
return tree;
}
template<class T>
//最大节点
T RBTree<T>::maximum()
{
RBTNode<T>* p = maximum(_root);
if (p)
{
return p->key;
}
return (T)nullptr;
}
template<class T>
//左旋
void RBTree<T>::leftRotate(RBTNode<T>*& root, RBTNode<T>* x)
{
RBTNode<T>* y = x->rc; // x的右子树设为y
x->rc = y->lc; //向左旋转
if (y->lc)
y->lc->parent = x; //更新父节点为x
y->parent = x->parent; //重设y的父节点为x的父节点
if (!x->parent) //如果是根节点
{
_root = y;
}
else
{
if (x->parent->lc == x)
{
x->parent->lc = y;
}
else
{
x->parent->rc = y;
}
}
y->lc = x; //完成旋转的后半部分
x->parent = y;
}
template<class T>
//右旋
void RBTree<T>::rightRotate(RBTNode<T>*& root, RBTNode<T>* x)
{
RBTNode<T>* y = x->lc; // x的左子树设为y
x->lc = y->rc; //向左旋转
if (y->rc)
y->rc->parent = x; //更新父节点为x
y->parent = x->parent; //重设y的父节点为x的父节点
if (!x->parent) //如果是根节点
{
_root = y;
}
else
{
if (x->parent->lc == x)
{
x->parent->lc = y;
}
else
{
x->parent->rc = y;
}
}
y->rc = x; //完成旋转的后半部分
x->parent = y;
}
template<class T>
//插入函数
void RBTree<T>::insert(RBTNode<T>*& root, RBTNode<T>* node)
{
RBTNode<T>* y = nullptr;
RBTNode<T>* x = root;
// 添加节点到树
while (x)
{
y = x;
if (node->key < x->key)
{
x = x->lc;
}
else {
x = x->rc;
}
}
node->parent = y;
if (y)
{
if (node->key < y->key)
{
y->lc = node;
}
else {
y->rc = node;
}
}
else
{
root = node;
}
// 设定节点颜色
node->color = RED;
// 修正树
insertFixUp(root, node);
}
template<class T>
//插入修正函数
void RBTree<T>::insertFixUp(RBTNode<T>*& root, RBTNode<T>* node)
{
RBTNode<T>* parent, * gparent;
// 若父节点存在,并且父节点的颜色是红色
while ((parent = node->parent) && parent->color==RED)
{
gparent = parent->parent;
if (parent == gparent -> lc) // 若父节点是祖父结点的左孩子
{
//如果叔叔节点是红色
RBTNode<T>* uncle = gparent->rc;
if (uncle && uncle->color == RED)
{
uncle->color = BLACK; // 改变颜色
parent->color = BLACK;
gparent->color = RED;
node = gparent;
continue;
}
//若叔叔节点是黑色,并且当前节点是右孩子
if (parent->rc == node)
{
RBTNode<T>* tmp;
leftRotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
//若叔叔节点是黑色,并且当前节点是左孩子
parent->color = BLACK;
gparent->color = RED;
rightRotate(root, gparent);
}
else //若父节点是祖父结点的右孩子
{
// 如果叔叔节点是红色
RBTNode<T>* uncle = gparent->lc;
if (uncle && uncle->color == RED)
{
uncle->color = BLACK;
parent->color = BLACK;
gparent->color = RED;
node = gparent;
continue;
}
// 如果叔叔是黑色,并且当前节点是左孩子
if (parent->lc == node)
{
RBTNode<T>* tmp;
rightRotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
// 如果叔叔是黑色,且当前节点是右孩子
parent->color = BLACK;
gparent->color = RED;
leftRotate(root, gparent);
}
}
root->color = BLACK; // 根节点设为黑色
}
template<class T>
//插入结点
void RBTree<T>::insert(T key)
{
RBTNode<T>* z = nullptr;
if ((z = new RBTNode<T>(key, BLACK, nullptr, nullptr, nullptr)) == nullptr)
{
return;
}
insert(_root, z);
}
template<class T>
//删除函数
void RBTree<T>::remove(RBTNode<T>*& root, RBTNode<T>* node)
{
RBTNode<T>* child, * parent;
RBTColor color;
// 如果被删除节点左右孩子都存在
if (node->lc && node->rc)
{
RBTNode<T>* replace = node; //取代的结点
//获取后继节点
replace = replace->rc;
while (replace->lc)
{
replace = replace->lc;
}
if (node->parent) // 如果不是根节点
{
if (node->parent->lc == node) // 如果是左结点
{
node->parent->lc = replace;
}
else
{
node->parent->rc = replace;
}
}
else
{
root = replace; //更新根节点
}
child = replace->rc; //replace必然不存在左孩子
parent = replace->parent; //保存父节点
color = replace->color; //保存颜色
if (parent == node) //如果被删除节点是后继街店的父节点
{
parent = replace;
}
else
{
if (child)
{
child->parent = parent;
}
parent->lc = child;
replace->rc = node->rc;
node->rc->parent = replace;
}
replace->parent = node->parent;
replace->color = node->color;
replace->lc = node->lc;
node->lc->parent = replace;
if (color == BLACK)
{
removeFixUp(root, child, parent);
}
delete node;
return;
}
if (node->lc)
{
child = node->lc;
}
else
{
child = node->rc;
}
parent = node->parent;
color = node->color;
if (child)
{
child->parent = parent;
}
if (parent)
{
if (parent->lc = node)
{
parent->lc = child;
}
else
{
parent->rc = child;
}
}
else
{
root = child;
}
if (color == BLACK)
{
removeFixUp(root, child, parent);
}
delete node;
}
template<class T>
//删除修正函数
void RBTree<T>::removeFixUp(RBTNode<T>*& root, RBTNode<T>* node, RBTNode<T>* parent)
{
RBTNode<T>* other;//node的兄弟节点
while ((!node || node->color == BLACK) && node != root) //node为非根节点、为空或为黑色节点
{
if (parent->lc == node) //如果是左孩子
{
other = parent->rc;
if (other->color == RED) // 如果兄弟为红
{
other->color = BLACK;
parent->color = RED;
leftRotate(root, parent);
other = parent->rc;
}
if ((!other->lc || other->lc->color == BLACK) && (!other->rc || other->rc->color == BLACK))
{
//如果兄弟和兄弟的孩子节点都是黑
other->color = RED;
node = parent;
parent = node->parent;
}
else
{
if (!other->rc || other->rc->color == BLACK)
{
//如果兄弟的右孩子是黑色
other->lc->color = BLACK;
other->color = RED;
rightRotate(root, other);
other = parent->rc;
}
//如果右孩子是红色的
other->color = parent->color;
parent->color = BLACK;
other->lc->color = BLACK;
rightRotate(root, parent);
node = root;
break;
}
}
}
if (node)
{
node->color = BLACK;
}
}
template<class T>
//删除结点
void RBTree<T>::remove(T key)
{
RBTNode<T> *res = search(_root, key);
if (res)
{
remove(_root, res);
}
}
template<class T>
void RBTree<T>::destroy(RBTNode<T>*& tree)
{
if (!tree)return;
if (tree->lc)
{
return destroy(tree->lc);
}
if (tree->rc)
{
return destroy(tree->rc);
}
delete tree;
tree = nullptr;
}
template<class T>
//销毁红黑树
void RBTree<T>::destroy()
{
destroy(_root);
}
template<class T>
void RBTree<T>::print(RBTNode<T>* tree, T key, int direction)
{
if (tree)
{
if (direction == 0)
{
cout << setw(2) << tree->key << "(B) is root" << endl;
}
else
{
cout << setw(2) << tree->key << (tree->color == RED ? "(R)" : "(B)");
}
print(tree->lc, tree->key, -1);
print(tree->rc, tree->key, 1);
}
}
template<class T>
void RBTree<T>::print()
{
if (_root)
{
print(_root, _root->key, 0);
}
}
template<class T>
//找数值大于x的最小结点
RBTNode<T>* RBTree<T>::successor(RBTNode<T>* x)
{
if (x->rc) //如果存在右孩子
{
return minimum(x->rc);
}
//如果不存在右孩子
RBTNode<T>* y = x->parent;
while (y && x == y->rc)
{
x = y;
y = y->parent;
}
return y;
}
template<class T>
//找数值小于x的最大结点
RBTNode<T>* RBTree<T>::predecessor(RBTNode<T>* x)
{
if (x->lc) //如果存在左孩子
{
return maximum(x->lc);
}
//如果不存在左孩子
RBTNode<T>* y = x->parent;
while (y && x == y->lc)
{
x = y;
y = y->parent;
}
return y;
}
#endif