一、概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。
性质:
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
二、红黑树的结点定义
enum Colour
{RED,BLACK
};template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Colour _col;RBTreeNode(T data = T()):_left(nullptr),_right(nullptr),_parent(nullptr),_data(data),_col(RED)
};
二、红黑树的插入
1、插入结点
Node* root = GetRoot();if (root == nullptr){root = new Node(data);root->_parent = _head;_head->_parent = root;return true;}Node* cur = root;Node* parent = root;//找到data节点插入的位置while (cur){if (data < cur->_data){parent = cur;cur = cur->_left;}else if (data > cur->_data){parent = cur;cur = cur->_right;}}//插入data节点cur = new Node(data);if (data < parent->_data){cur->_parent = parent;parent->_left = cur;}else{cur->_parent = parent;parent->_right = cur;}
若插入结点的父亲为黑色,则结束。
若插入结点的父亲为红色,则出现了连续的红色结点,违反规则,需要处理。
2、调整
如插入结点后,该树违反了红黑树的规则,则对其进行调整。
(1)cur红,parent红,gparent黑,uncle存在且红
可以看出,该结点插入后,违反了规则: 如果一个节点是红色的,则它的两个孩子结点是黑色的。
此时,需要对其进行变色:将parent、uncle改为黑,gparent改为红,然后将gparent赋值给cur,若此时cur的父结点为红,则继续向上调整。
(2)cur红,parent红,gparent黑,uncle不存在
此时cur一定是新插入的结点。否则不符合红黑树的规则:不能出现连在一起的红色结点。调整后:
(3)cur红,parent红,gparent黑,uncle存在且为黑
(1)基础情况
此时cur一定不是新增结点,cur一定是由黑色变为红色的,否则就违反了红黑树的规则:每条路径黑色结点相同。
cur变红前的一种可能情况:
注:c:包含一个黑色结点的红黑树 (4种)
d/e:null或一个红色结点(4种)
调整后(旋转+变色):
我们将parent变为黑色,而非将cur变为黑色(即parent为红,cur和gparent为黑),是因为如果parent为红,那么当parent不是根结点的时候,仍需向上处理,即parent为红非终结态。
(2)单旋后转变为基础情况
对于这种情况,我们需要做以下处理:
若parent为gparent的左孩子,cur为parent的右孩子,则针对parent做左单旋转;
若parent为gparent的右孩子,cur为parent的左孩子,则针对parent做右单旋转。
旋转完成后,即转变为基础情况:
3、插入完整代码
bool Insert(const T& data){Node* root = GetRoot();if (root == nullptr){root = new Node(data);root->_parent = _head;_head->_left = root;_head->_right = root;_head->_parent = root;root->_col = BLACK;return true;}Node* cur = root;Node* parent = root;//找到data节点插入的位置while (cur){if (data < cur->_data){parent = cur;cur = cur->_left;}else if (data > cur->_data){parent = cur;cur = cur->_right;}else{return false;}}//插入data节点cur = new Node(data);if (data < parent->_data){cur->_parent = parent;parent->_left = cur;}else{cur->_parent = parent;parent->_right = cur;}//更新_head结点链接关系T min = _head->_left->_data;T max = _head->_right->_data;if (data < min){_head->_left = cur;}if (data > max){_head->_right = cur;}//调整while (parent && parent->_col == RED){Node* gparent = parent->_parent;if (parent == gparent->_left){Node* uncle = gparent->_right;//cur红,parent红,gparent黑,uncle存在且红if (uncle && uncle->_col == RED){//调整颜色parent->_col = uncle->_col = BLACK;gparent->_col = RED;//继续向上处理cur = gparent;parent = cur->_parent;}else if(uncle == nullptr){//cur红,parent红,gparent黑,uncle不存在if (cur == parent->_left){//右旋RotateR(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{RotateL(parent);RotateR(gparent);//变色cur->_col = BLACK;parent->_col = gparent->_col = RED;}}else if (uncle && uncle->_col == BLACK){//cur红,parent红,gparent黑,uncle存在且为黑if (cur == parent->_left){RotateR(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{//对parent左单旋后转变为上面的情况RotateL(parent);RotateR(gparent);//变色cur->_col = BLACK;gparent->_col = RED;}}}else if(parent = gparent->_right){Node* uncle = gparent->_left;//cur红,parent红,gparent黑,uncle存在且红if (uncle && uncle->_col == RED){//调整颜色parent->_col = uncle->_col = BLACK;gparent->_col = RED;//继续向上处理cur = gparent;parent = cur->_parent;}else if (uncle == nullptr){//cur红,parent红,gparent黑,uncle不存在if (cur == parent->_right){//左旋RotateL(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{RotateR(parent);RotateL(gparent);//变色cur->_col = BLACK;parent->_col = gparent->_col = RED;}}else if (uncle && uncle->_col == BLACK){//cur红,parent红,gparent黑,uncle存在且为黑if (cur == parent->_right){RotateL(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{//对parent右单旋后转变为上面的情况RotateR(parent);RotateL(gparent);//变色cur->_col = BLACK;gparent->_col = RED;}}}}_head->_parent->_col = BLACK;return true;}
三、验证是否为红黑树
验证是否为红黑树,则需要根据红黑树的规则来确定:
没有两个连续的红色结点;
每条路径包含相同的黑色结点。
bool IsValidRBTRee(){Node* root = GetRoot();if (root->_col == RED){return false;}if (root == nullptr){return true;}int blackc = GetBlackCount(GetRoot());int blacknum = 0;_IsValidRBTRee(GetRoot(), blackc, blacknum);}bool _IsValidRBTRee(Node* root, size_t blackCount, size_t pathBlack){if (root == nullptr){pathBlack++;if (pathBlack != blackCount){cout << "各路径黑色结点数量不同" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){return false;}if (root->_col == BLACK){pathBlack++;}return _IsValidRBTRee(root->_left, blackCount, pathBlack)&& _IsValidRBTRee(root->_right, blackCount, pathBlack);}
四、完整代码
enum Colour
{RED,BLACK
};template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Colour _col;RBTreeNode(T data = T()):_left(nullptr),_right(nullptr),_parent(nullptr),_data(data),_col(RED){}
};// 请模拟实现红黑树的插入--注意:为了后序封装map和set,本文在实现时给红黑树多增加了一个头结点
template<class T>
class RBTree
{typedef RBTreeNode<T> Node;
public:RBTree(){_head = new Node;_head->_left = _head;_head->_right = _head;_head->_parent = _head;}// 在红黑树中插入值为data的节点,插入成功返回true,否则返回false// 注意:为了简单起见,本次实现红黑树不存储重复性元素bool Insert(const T& data){Node* root = GetRoot();if (root == nullptr){root = new Node(data);root->_parent = _head;_head->_left = root;_head->_right = root;_head->_parent = root;root->_col = BLACK;return true;}Node* cur = root;Node* parent = root;//找到data节点插入的位置while (cur){if (data < cur->_data){parent = cur;cur = cur->_left;}else if (data > cur->_data){parent = cur;cur = cur->_right;}else{return false;}}//插入data节点cur = new Node(data);if (data < parent->_data){cur->_parent = parent;parent->_left = cur;}else{cur->_parent = parent;parent->_right = cur;}//更新_head结点链接关系T min = _head->_left->_data;T max = _head->_right->_data;if (data < min){_head->_left = cur;}if (data > max){_head->_right = cur;}//调整while (parent && parent->_col == RED){Node* gparent = parent->_parent;if (parent == gparent->_left){Node* uncle = gparent->_right;//cur红,parent红,gparent黑,uncle存在且红if (uncle && uncle->_col == RED){//调整颜色parent->_col = uncle->_col = BLACK;gparent->_col = RED;//继续向上处理cur = gparent;parent = cur->_parent;}else if(uncle == nullptr){//cur红,parent红,gparent黑,uncle不存在if (cur == parent->_left){//右旋RotateR(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{RotateL(parent);RotateR(gparent);//变色cur->_col = BLACK;parent->_col = gparent->_col = RED;}}else if (uncle && uncle->_col == BLACK){//cur红,parent红,gparent黑,uncle存在且为黑if (cur == parent->_left){RotateR(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{//对parent左单旋后转变为上面的情况RotateL(parent);RotateR(gparent);//变色cur->_col = BLACK;gparent->_col = RED;}}}else if(parent = gparent->_right){Node* uncle = gparent->_left;//cur红,parent红,gparent黑,uncle存在且红if (uncle && uncle->_col == RED){//调整颜色parent->_col = uncle->_col = BLACK;gparent->_col = RED;//继续向上处理cur = gparent;parent = cur->_parent;}else if (uncle == nullptr){//cur红,parent红,gparent黑,uncle不存在if (cur == parent->_right){//左旋RotateL(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{RotateR(parent);RotateL(gparent);//变色cur->_col = BLACK;parent->_col = gparent->_col = RED;}}else if (uncle && uncle->_col == BLACK){//cur红,parent红,gparent黑,uncle存在且为黑if (cur == parent->_right){RotateL(gparent);//变色parent->_col = BLACK;gparent->_col = RED;}else{//对parent右单旋后转变为上面的情况RotateR(parent);RotateL(gparent);//变色cur->_col = BLACK;gparent->_col = RED;}}}}_head->_parent->_col = BLACK;return true;}// 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptrNode* Find(const T& data){Node* cur = GetRoot();Node* parent = cur;while (cur){if (data > cur->_data){parent = cur;cur = cur->_right;}else if (data < cur->_data){parent = cur;cur = cur->_left;}else{return cur;}}return nullptr;}// 获取红黑树最左侧节点Node* LeftMost(){return _head->_left;}// 获取红黑树最右侧节点Node* RightMost(){return _head->_right;}// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测bool IsValidRBTRee(){Node* root = GetRoot();if (root->_col == RED){return false;}if (root == nullptr){return true;}int blackc = GetBlackCount(GetRoot());int blacknum = 0;_IsValidRBTRee(GetRoot(), blackc, blacknum);}void InOrder(){_InOrder(GetRoot());}
private:void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_data << " ";_InOrder(root->_right);}size_t GetBlackCount(Node* root){size_t ret = 0;Node* cur = root;while (cur){if (cur->_col == BLACK){ret++;}cur = cur->_left;}ret++;return ret;}bool _IsValidRBTRee(Node* root, size_t blackCount, size_t pathBlack){if (root == nullptr){pathBlack++;if (pathBlack != blackCount){cout << "各路径黑色结点数量不同" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){return false;}if (root->_col == BLACK){pathBlack++;}return _IsValidRBTRee(root->_left, blackCount, pathBlack)&& _IsValidRBTRee(root->_right, blackCount, pathBlack);}// 右单旋void RotateR(Node* parent){Node* pprent = parent->_parent;Node* pl = parent->_left;Node* PRL = pl->_right;Node* PR = parent;//更新与上一节点的链接关系if (parent == GetRoot()){_head->_parent = pl;pl->_parent = nullptr;}else{if (pprent->_left == parent){pprent->_left = pl;}else{pprent->_right = pl;}pl->_parent = pprent;}pl->_right = PR;PR->_parent = pl;PR->_left = PRL;if (PRL)PRL->_parent = PR;}// 左单旋void RotateL(Node* parent){Node* pprent = parent->_parent;Node* pr = parent->_right;Node* PLR = pr->_left;Node* PL = parent;//更新与上一节点的链接关系if (parent == GetRoot()){_head->_parent = pr;pr->_parent = nullptr;}else{if (pprent->_left == parent){pprent->_left = pr;}else{pprent->_right = pr;}pr->_parent = pprent;}pr->_left = PL;PL->_parent = pr;PL->_right = PLR;if (PLR)PLR->_parent = PL;}// 为了操作树简单起见:获取根节点Node* GetRoot(){if (_head->_parent == _head){return nullptr;}else{return _head->_parent;}}
private:Node* _head;
};