"除开隐忍当下,与展望未来。我们别无他法"
红黑树的概念和它名字一样。其本质就是一颗二叉树。
但在每个节点 增加一存储 颜色(enum)。
核心:确保最长路径 不超过 最短路径的两倍!
相对于概念,红黑树的性质是重中之重!
1.每个节点不是红色就是黑色(这相当屁话).
2.根节点(root)一定是黑色.
3.不会存在连续的红色节点.
4.每条路径的黑色节点相同.
只有保证上述四点,才能保证红黑树的一条根本性质:
最长路径 不超过 最短路径的两倍!
废话不多讲,接下来进行实现。
这里的红黑树我们选择使用 K,V结构模拟实现。这样更方便 进行map/set的封装
- //记录节点的 属性
- enum Colour
- {
- RED,
- BLACK
- };
-
- template<class K,class V>
- struct RBTreeNode
- {
- RBTreeNode
* _left; - RBTreeNode
* _right; - RBTreeNode
* _parent; - pair
_kv; - Colour _col;
-
- RBTreeNode(const pair
kv) - :_left(nullptr),
- _right(nullptr),
- _parent(nullptr),
- _kv(kv),
- _col(RED) //默认给红色
- {}
-
- };
-
- template<class K,class V>
- struct RBTree
- {
- typedef RBTreeNode
Node; - RBTree()
- :_root(nullptr)
- {}
- Node* _root;
- };
同前篇AVL树一样,先把比较简单的部分 搭建起来。对于红黑树的删除和AVL树一样,也不会提出来。
简易:
- void _Destroy(Node* root)
- {
- if (root == nullptr)
- return;
-
- _Destroy(root->_left);
- _Destroy(root->_right);
- delete root;
- }
-
- ~RBTree()
- {
- _Destroy(_root);
- _root = nullptr;
- }
-
- //查找 是 根据key值来的
- Node* find(const K& k)
- {
- Node* cur = _root;
- //和AVL 树一样
- while (cur)
- {
- if (k > cur->_kv.first)
- {
- cur = cur->_right;
- }
- else if (k < cur->_kv.first)
- {
- cur = cur->_left;
- }
- else
- {
- return cur;
- }
- }
- return nullptr;
- }
- bool _CheckBalance(Node* root, int blacknum, int count)
- {
- //当root走到空 时 也就是统计完了 数字
- if (root == nullptr)
- {
- if (count != blacknum)
- {
- cout << "黑色节点数不够" << endl;
- return false;
- }
- return true;
- }
-
- //连续红色节点
- if (root->_col == RED && root->_parent->_col == RED)
- {
- cout << "连续红色节点" << endl;
- return false;
- }
-
- if (root->_col == BLACK)
- {
- count++;
- }
-
- return _CheckBalance(root->_left, blacknum, count)
- && _CheckBalance(root->_right, blacknum, count);
- }
-
- bool CheckBalance()
- {
- if (_root == nullptr)
- return true;
-
- if (_root->_col == RED)
- {
- cout << "根节点是红色" << endl;
- return false;
- }
-
- int blacknum = 0;
- //我们从最左边
- //记录标准值
- Node* left = _root;
- while (left)
- {
- if (left->_col == BLACK)
- {
- ++blacknum;
- }
- left = left->_left;
- }
- //其他路径的 黑色节点
- int count = 0;
- return _CheckBalance(_root,blacknum,count);
- }
总的来说,就是分为三种情况,且uncle节点是分析的关键。
1.p为黑色,那么不管在那里插入。都不会有影响。
2.p为红色,且uncle存在为红色;
uncle+p -->红色 g--->黑色 如果g为根就停止,不为根 继续向上调整
3.p为红色,且uncle不存在或者为红色;
单旋+变色
如果cur 与parent 不同向, 双旋+变色
此时,我们需要的左右旋 其实已经在AVL树中实现过,并且这里不需要再处理平衡因子了。
-
- void RotateR(Node* parent)
- {
- Node* sub = parent->_left;
- Node* subLR = sub->_right;
-
- //让subLR去做parent的左
- parent->_left = subLR;
- //subLR可能不存在
- if (subLR)
- subLR->_parent = parent;
-
- sub->_right = parent;
- //记录 父节点 因为 sub 可能不是唯一独立的树
- Node* grandparent = parent->_parent;
- parent->_parent = sub;
-
- if (parent == _root)
- {
- //独立树
- _root = sub;
- sub->_parent = nullptr;
- }
- else
- {
- //子树
- //parent的 父亲仍然保留着 节点地址
- if (grandparent->_left == parent)
- {
- grandparent->_left = sub;
- }
- else
- {
- grandparent->_right = sub;
- }
-
- //更新回来
- sub->_parent = grandparent;
- }
- }
-
- void RotateL(Node* parent)
- {
- Node* sub = parent->_right;
- Node* subRL = sub->_left;
-
- //让subRL 去做parent的右边
- parent->_right = subRL;
- //仍然注意避坑
- if (subRL)
- subRL->_parent = parent;
-
- Node* grandparent = parent->_parent;
- sub->_left = parent;
- parent->_parent = sub;
-
- if (parent == _root)
- {
- _root = sub;
- sub->_parent = nullptr;
- }
- else
- {
- if (grandparent->_left == parent)
- {
- grandparent->_left = sub;
- }
- else
- {
- grandparent->_right = sub;
- }
- sub->_parent = grandparent;
- }
- }
调整红黑平衡。
- //调整红黑色
- while (parent && parent->_col == RED)
- {
- //祖父
- Node* grandfather = parent->_parent;
-
- if (grandfather->_left == parent)
- {
- //uncle 关键
- Node* uncle = grandfather->_right;
- //uncle 存在且为红
- if (uncle && uncle->_col == RED)
- {
- uncle->_col = parent->_col = BLACK;
- grandfather->_col = RED;
-
- //继续往上处理
- cur = grandfather;
- parent = cur->_parent;
- }
- else
- {
- //uncle 不存在
- //判断直线和折线
- //此时父节点 在左边
- if (cur == parent->_left)
- {
- //单旋
- RotateR(grandfather);
-
- //变色
- parent->_col = BLACK;
- grandfather->_col = RED;
- }
- else
- {
- RotateL(parent);
- RotateR(grandfather);
-
- cur->_col = BLACK;
- grandfather->_col = RED;
- }
-
- break;
- }
- }
- else //右边(parent)
- {
- Node* uncle = grandfather->_left;
- if (uncle && uncle->_col == RED)
- {
- uncle->_col = parent->_col = BLACK;
- grandfather->_col = RED;
-
- //继续往上处理
- cur = grandfather;
- parent = cur->_parent;
- }
- else
- {
- //uncle不存在
- //parent在右边
- if (cur == parent->_right)
- {
- RotateL(grandfather);
-
- parent->_col = BLACK;
- grandfather->_col = RED;
- }
- else
- {
- RotateR(parent);
- RotateL(grandfather);
-
- cur->_col = BLACK;
- grandfather->_col = RED;
- }
-
- break; //插入结束
- }
- }
- }
红黑树是一个效率很高的树(增删查改可以近似LogN),它可以达到近似平衡的树。
相比较于AVL树,它在翻转的次数更少。没那么严格。
在这一方面,翻转的代价很小。
'
这就是本篇的主要内容啦。感谢您的阅读
祝你好远~