红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
最短路径:全黑;最长路径:一黑一红交替。
由于avl树要求严格的平衡,因此相比于红黑树来说需要更频繁的旋转来保证平衡,所以整体而言效率是比红黑树要低一点。
//枚举颜色
enum Color {
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode {
RBTreeNode(const pair<const K, V>& kv)
:_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED)
{ }
pair<const K, V> _kv;
//需要再增加一个结点颜色信息
Color _col;
RBTreeNode<const K, V>* _left;
RBTreeNode<const K, V>* _right;
//同样是需要父亲结点,后续调整旋转需要找到父亲
RBTreeNode<const K, V>* _parent;
};
往已经是满足红黑树性质的树中插入一个结点时,待插入结点的颜色一定要设置为红色,为什么?
若插入一个黑色结点,那么必然会违反性质4,若插入红色节点则不一定会违反性质3。
红黑树插入的关键在于要看叔叔结点的颜色,具体情况可分为两种:
红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O( l o g 2 N log_2 N log2N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。
#pragma once
#include
using namespace std;
enum Color {
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode {
RBTreeNode(const pair<const K, V>& kv)
:_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED)
{
}
pair<const K, V> _kv;
enum Color _col;
RBTreeNode<const K, V>* _left;
RBTreeNode<const K, V>* _right;
RBTreeNode<const K, V>* _parent;
};
template<class K, class V>
class RBTree {
typedef RBTreeNode<const K, V> Node;
public:
bool insert(const pair<const K, V>& kv) {
if (!_root) {
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* 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 = new Node(kv);
if (parent->_kv.first < kv.first) {
parent->_right = cur;
}
else {
parent->_left = cur;
}
cur->_parent = parent;
//parent为红需要一直往上调整
while (parent && parent->_col == RED) {
Node* grandpa = parent->_parent;
if (grandpa->_left == parent) {
Node* uncle = grandpa->_right;
//叔叔存在且为红
if (uncle && uncle->_col == RED) {
//把父亲和叔叔染黑
//爷爷染红继续往上调整
parent->_col = uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
//叔叔不存在或者存在且为黑
else {
//单纯的一边高(直线)单旋
if (cur == parent->_left) {
rotateRight(grandpa);
parent->_col = BLACK;
cur->_col = grandpa->_col = RED;
}
//折线情况需要双旋
else {
rotateLeft(parent);
rotateRight(grandpa);
cur->_col = BLACK;
parent->_col = grandpa->_col = RED;
}
break;
}
}
//同样的逻辑
else {
Node* uncle = grandpa->_left;
if (uncle && uncle->_col == RED) {
parent->_col = uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
else {
if (parent->_right == cur) {
rotateLeft(grandpa);
grandpa->_col = cur->_col = RED;
parent->_col = BLACK;
}
else {
rotateRight(parent);
rotateLeft(grandpa);
parent->_col = grandpa->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
bool isBlance() {
if (_root->_col != BLACK) {
return false;
}
int cnt = 0;
Node* cur = _root;
while (cur) {
cnt += cur->_col == BLACK;
cur = cur->_left;
}
return _isBlance(_root, 0, cnt);
}
int getHeight() {
return getHeight(_root);
}
private:
int getHeight(Node* root) {
if (!root) {
return 0;
}
int leftH = getHeight(root->_left);
int rightH = getHeight(root->_right);
return max(leftH, rightH) + 1;
}
bool _isBlance(Node* root, int blackcnt, int t) {
if (!root) {
cout << blackcnt << ' ' << t << endl;
return t == blackcnt;
}
if (root->_col == RED && root->_parent && root->_parent->_col == RED) {
return false;
}
return _isBlance(root->_left, blackcnt + (root->_col == BLACK), t) && _isBlance(root->_right, blackcnt + (root->_col == BLACK), t);
}
void rotateLeft(Node* parent) {
Node* cur = parent->_right;
Node* curleft = cur->_left;
if (curleft) {
curleft->_parent = parent;
}
parent->_right = curleft;
cur->_left = parent;
Node* oldparent = parent->_parent;
parent->_parent = cur;
cur->_parent = oldparent;
if (!oldparent) {
_root = cur;
}
else {
if (oldparent->_left == parent) {
oldparent->_left = cur;
}
else {
oldparent->_right = cur;
}
}
}
void rotateRight(Node* parent) {
Node* cur = parent->_left;
Node* curright = cur->_right;
if (curright) {
curright->_parent = parent;
}
parent->_left = curright;
cur->_right = parent;
Node* oldparent = parent->_parent;
parent->_parent = cur;
cur->_parent = oldparent;
if (!oldparent) {
_root = cur;
}
else {
if (oldparent->_left == parent) {
oldparent->_left = cur;
}
else {
oldparent->_right = cur;
}
}
}
private:
Node* _root = nullptr;
};