文章目录
- 3.红黑树
- 3.1概念
- 3.2 性质
- 3.3 RBTree的实现
- 3.3.1 insert的框架
- 3.3.2 insert的处理
- 3.3.3 中序遍历
- 3.3.4检查是否平衡和获取树的高度
- 3.4完整代码
3.红黑树
3.1概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
3.2 性质
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的, 说明树里面不能出现连续的红色节点
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点), 这个性质是为了方便数树有几条路径
问题: 为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?
解答: 根据性质3和性质4可知, 如果有一颗红黑树, 那么它的最短路径应是全黑节点, 最长路径应是一红一黑节点交替
于是, 我们可以得到一个结论, 假设每条路径有N个黑色节点, 那么每条路径的节点个数为[N, 2N]. 这样就满足了问题红黑树的特征, 即
最长路径中节点个数不会超过最短路径节点个数的两倍
3.3 RBTree的实现
3.3.1 insert的框架
与前面的avl树类似
#pragma once
enum Color
{RED,BLACK
};template<class K, class V>
struct RBTreeNode
{RBTreeNode(const pair<K, V>& kv) : _kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _bf(RED) {}RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> _kv;Color _color;
};template<class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public:bool insert(const pair<K, V>& kv){// a. 树为空,则直接新增节点,赋值给root指针if (_root == nullptr) {_root = new Node(kv);// 根节点是黑色的_root->_color = BLACK;return true;}// b. 树不空,按二叉搜索树性质查找插入位置,插入新节点Node* cur = _root, * parent = nullptr;while (cur) {if (cur->_kv.first < kv.first) {parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first) {parent = cur;cur = cur->_left;}else return false;}// cur为空,找到了一个合适的位置,此时需要链接,注意链接位置cur = new Node(kv);// cur->_color = ?? if (kv.first < parent->_kv.first) {parent->_left = cur;cur->_parent = parent;}else {parent->_right = cur;cur->_parent = parent;}// new code....return true;}
private:Node* _root = nullptr;
};
3.3.2 insert的处理
新增节点, 选择红色, 因为黑色会影响其他路径
- 新增节点的父亲是黑色的, 不需要处理
- 新增节点的父亲是红色的, 需要处理
(变色)or(变色+旋转)规定cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
情况1: cur为红,p为红,g为黑, u 存在且为红 \textcolor{red}{u存在且为红} u存在且为红
while (parent && parent->_color == RED) {Node* grandparent = parent->_parent;if (parent == grandparent->_left) {Node* uncle = grandparent->_right;// uncle存在且为红, 情况1if (uncle && uncle->_color == RED) {// g(b)// p(r) u(r)// c(r)// 变色parent->_color = uncle->_color = BLACK;grandparent->_color = RED;// 继续向上处理cur = grandparent;parent = cur->_parent;}}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
情况2:cur为红,p为红,g为黑, u 不存在 / u 存在且为黑 \textcolor{red}{u不存在/u存在且为黑} u不存在/u存在且为黑
while (parent && parent->_color == RED) {Node* grandparent = parent->_parent;if (parent == grandparent->_left) {Node* uncle = grandparent->_right;// uncle存在且为红, 情况1if (uncle && uncle->_color == RED) {// g(b)// p(r) u(r)// c(r)// 变色parent->_color = uncle->_color = BLACK;grandparent->_color = RED;// 继续向上处理cur = grandparent;parent = cur->_parent;}// uncle为黑或者不存在else {// cur在parent的左边, 情况2, 单旋if (cur = parent->_left) {// g(b)// p(r) u(b)// c(r)RotateR(grandparent);parent->_color = BLACK;grandparent->_color = RED;}break;}}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
情况3:cur为红,p为红,g为黑, u 不存在 / u 存在且为黑 \textcolor{red}{u不存在/u存在且为黑} u不存在/u存在且为黑, cur的位置与前面不同
while (parent && parent->_color == RED) {Node* grandparent = parent->_parent;if (parent == grandparent->_left) {Node* uncle = grandparent->_right;// uncle存在且为红, 情况1if (uncle && uncle->_color == RED) {// g(b)// p(r) u(r)// c(r)// 变色parent->_color = uncle->_color = BLACK;grandparent->_color = RED;// 继续向上处理cur = grandparent;parent = cur->_parent;}// uncle为黑或者不存在else {// cur在parent的左边, 情况2, 单旋if (cur = parent->_left) {// g(b)// p(r) u(b)// c(r)RotateR(grandparent);parent->_color = BLACK;grandparent->_color = RED;}// cur在parent的右边, 情况3, 双旋else {// g(b)// p(r) u(b)// c(r)RotateL(parent);RotateR(grandparent);cur->_color = BLACK;grandparent->_color = RED;}break;}}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
完善else条件
while (parent && parent->_color == RED) {Node* grandparent = parent->_parent;if (parent == grandparent->_left) {Node* uncle = grandparent->_right;// uncle存在且为红, 情况1if (uncle && uncle->_color == RED) {// g(b)// p(r) u(r)// c(r)// 变色parent->_color = uncle->_color = BLACK;grandparent->_color = RED;// 继续向上处理cur = grandparent;parent = cur->_parent;}// uncle为黑或者不存在else {// cur在parent的左边, 情况2, 单旋if (cur = parent->_left) {// g(b)// p(r) u(b)// c(r)RotateR(grandparent);parent->_color = BLACK;grandparent->_color = RED;}// cur在parent的右边, 情况3, 双旋else {// g(b)// p(r) u(b)// c(r)RotateL(parent);RotateR(grandparent);cur->_color = BLACK;grandparent->_color = RED;}break;}}// parent == grandparent->_rightelse {// uncle存在且为红, 情况1if (uncle && uncle->_color == RED) {// g(b)// u(r) p(r)// c(r)// 变色parent->_color = uncle->_color = BLACK;grandparent->_color = RED;// 继续向上处理cur = grandparent;parent = cur->_parent;}// uncle为黑或者不存在else {// cur在parent的右边, 情况2, 单旋if (cur = parent->_right) {// g(b)// u(b) p(r)// c(r)RotateL(grandparent);parent->_color = BLACK;grandparent->_color = RED;}// cur在parent的右边, 情况3, 双旋else {// g(b)// u(r) p(b)// c(r)RotateR(parent);RotateL(grandparent);cur->_color = BLACK;grandparent->_color = RED;}break;}}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
return true;
3.3.3 中序遍历
void InOrder()
{_InOrder(_root);cout << endl;
}
void _InOrder(Node* root)
{if (root == nullptr) return;_InOrder(root->_left);cout << root->_kv.first << ' ';_InOrder(root->_right);
}
3.3.4检查是否平衡和获取树的高度
bool IsBalance()
{if (_root == nullptr) return true;// 违反规则2if (_root->_color == RED) return false;int refVal = 0; // 参考值, 记录某一条路径上的黑色节点的数量Node* cur = _root;while (cur) {if (cur->_color == BLACK)refVal++;cur = cur->_left;}int blackNum = 0;return Check(_root, refVal, blackNum);
}bool Check(Node* root, const int& refVal, int blackNum)
{if (root == nullptr) { // cout << blackNum << endl;if(blackNum == refVal)return true; else {cout << "有路径黑色节点数量不一致" << endl;return false;}}if (root->_color == BLACK) blackNum++;if (root->_color == RED && root->_parent->_color == RED) {// 违反规则3cout << "有连续的红色节点" << endl;return false;}return Check(root->_left, refVal, blackNum) && Check(root->_right, refVal, blackNum);
}
int GetHeight()
{return _GetHeight(_root);
}
int _GetHeight(Node* root)
{if (root == nullptr) return 0;int left = _GetHeight(root->_left);int right = _GetHeight(root->_right);return left > right ? left + 1 : right + 1;
}
3.4完整代码
#pragma once
#include <iostream>
#include <vector>
using namespace std;
enum Color
{RED,BLACK
};template<class K, class V>
struct RBTreeNode
{RBTreeNode(const pair<K, V>& kv) : _kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _color(RED) {}RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> _kv;Color _color;
};template<class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public:bool insert(const pair<K, V>& kv){// a. 树为空,则直接新增节点,赋值给root指针if (_root == nullptr) {_root = new Node(kv);// 根节点是黑色的_root->_color = BLACK;return true;}// b. 树不空,按二叉搜索树性质查找插入位置,插入新节点Node* cur = _root, *parent = nullptr;while (cur) {if (cur->_kv.first < kv.first) {parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first) {parent = cur;cur = cur->_left;}else return false;}// cur为空,找到了一个合适的位置,此时需要链接,注意链接位置cur = new Node(kv);cur->_color = RED; // 新增节点给红色if (parent->_kv.first < kv.first) {parent->_right = cur;cur->_parent = parent;}else {parent->_left = cur;cur->_parent = parent;}while (parent && parent->_color == RED) {Node* grandparent = parent->_parent;if (parent == grandparent->_left) {Node* uncle = grandparent->_right;// uncle存在且为红, 情况1if (uncle && uncle->_color == RED) {// g(b)// p(r) u(r)// c(r)// 变色parent->_color = uncle->_color = BLACK;grandparent->_color = RED;// 继续向上处理cur = grandparent;parent = cur->_parent;}// uncle为黑或者不存在else {// cur在parent的左边, 情况2, 单旋if (cur == parent->_left) {// g(b)// p(r) u(b)// c(r)RotateR(grandparent);parent->_color = BLACK;grandparent->_color = RED;}// cur在parent的右边, 情况3, 双旋else {// g(b)// p(r) u(b)// c(r)RotateL(parent);RotateR(grandparent);cur->_color = BLACK;grandparent->_color = RED;}break;}}// parent == grandparent->_rightelse {Node* uncle = grandparent->_left;// uncle存在且为红, 情况1if (uncle && uncle->_color == RED) {// g(b)// u(r) p(r)// c(r)// 变色parent->_color = uncle->_color = BLACK;grandparent->_color = RED;// 继续向上处理cur = grandparent;parent = cur->_parent;}// uncle为黑或者不存在else {// cur在parent的右边, 情况2, 单旋if (cur == parent->_right) {// g(b)// u(b) p(r)// c(r)RotateL(grandparent);parent->_color = BLACK;grandparent->_color = RED;}// cur在parent的左边, 情况3, 双旋else {// g(b)// u(r) p(b)// c(r)RotateR(parent);RotateL(grandparent);cur->_color = BLACK;grandparent->_color = RED;}break;}}}// 处理后_root可能会变色, 在这里它置为黑色_root->_color = BLACK;return true;}void InOrder(){_InOrder(_root);cout << endl;}bool IsBalance(){if (_root == nullptr) return true;// 违反规则2if (_root->_color == RED) return false;int refVal = 0; // 参考值, 记录某一条路径上的黑色节点的数量Node* cur = _root;while (cur) {if (cur->_color == BLACK)refVal++;cur = cur->_left;}int blackNum = 0;return Check(_root, refVal, blackNum);}// 获得树的高度size_t GetHeight(){return _GetHeight(_root);}// 获得节点数size_t GetSize(){return _GetSize(_root);}
private:Node* _root = nullptr;
protected:// 新节点插入较高右子树的右侧---右右:左单旋 void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;// 由于parent不一定是整棵树的根,后面更新subR的parent时需要用到parentParentNode* parentParent = parent->_parent;parent->_right = subRL;// 注意,subRL可能为nullptrif (subRL)subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;if (parent == _root) {_root = subR;subR->_parent = nullptr;}// parent不是整棵树的根else {if (parentParent->_left == parent)parentParent->_left = subR;elseparentParent->_right = subR;}subR->_parent = parentParent;}// 新节点插入较高左子树的左侧---左左:右单旋 void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;Node* parentParent = parent->_parent;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;parent->_parent = subL;if (parent == _root) {_root = subL;subL->_parent = nullptr;}else {if (parent == parentParent->_left)parentParent->_left = subL;elseparentParent->_right = subL;subL->_parent = parentParent;}}void _InOrder(Node* root){if (root == nullptr) return;_InOrder(root->_left);cout << root->_kv.first << ' ';_InOrder(root->_right);}bool Check(Node* root, const int& refVal, int blackNum){if (root == nullptr) { // cout << blackNum << endl;if(blackNum == refVal)return true; else {cout << "有路径黑色节点数量不一致" << endl;return false;}}if (root->_color == BLACK) blackNum++;if (root->_color == RED && root->_parent->_color == RED) {// 违反规则3cout << "有连续的红色节点" << endl;return false;}return Check(root->_left, refVal, blackNum) && Check(root->_right, refVal, blackNum);}size_t _GetHeight(Node* root){if (root == nullptr) return 0;size_t left = _GetHeight(root->_left);size_t right = _GetHeight(root->_right);return left > right ? left + 1 : right + 1;}size_t _GetSize(Node* root){if (root == nullptr) return 0;else return _GetSize(root->_left) + _GetSize(root->_right) + 1;}
};