概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。
规则:
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
插入
其实对于红黑树来说其实就是维护好一个规则,我们插入的时候每次除了第一个节点是插入节点是黑色,以后插入的新节点都是红色,插入完我们再判断是否需要去修改颜色,和旋转。修改颜色和旋转也是有公式的。
检测新节点插入后,红黑树的性质是否造到破坏
因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何
性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连
在一起的红色节点,此时需要对红黑树分情况来讨论:
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
情况一
每次当我们修改完颜色之后还需要向上循环去继续修改。
情况二
cur为红,p为红,g为黑,u不存在/u存在且为黑
情况三
其实就是需要双旋的情况
代码:
cpp
bool insert(const K&key,const V&value)
{
if (_node == nullptr)
{
_node = new rbtreeNode(make_pair(key, value));
_node->_col = BLACK;
return true;
}
rbtreeNode* root = _node;
rbtreeNode* rootp = _node;
while (root)
{
if (key < root->_kv.first)
{
rootp = root;
root = root->_left;
}
else if(key>root->_kv.first)
{
rootp = root;
root = root->_right;
}
else
{
break;
}
}
rbtreeNode* newnode = new rbtreeNode(make_pair(key,value));
if (key < rootp->_kv.first)
{
rootp->_left = newnode;
}
else
{
rootp->_right = newnode;
}
newnode->_parent = rootp;
newnode->_col = RED;
rbtreeNode* cur = newnode;
while (rootp&&rootp->_col==RED)
{
rbtreeNode* grandfather = rootp->_parent;
if (grandfather->_left == rootp)// u存在且为红 -》变色再继续往上处理
{
rbtreeNode* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)
{
uncle->_col = rootp->_col = BLACK;
grandfather->_col = RED;
cur = rootp;
rootp = rootp->_parent;
if (rootp == _node)
break;
}
else
{
if (rootp->_left == cur)
{
// g
// p u
//c
//单旋
rotateR(grandfather);
rootp->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p u
// c
//双旋
rotateL(rootp);
rotateR(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
break;
}
}
else
{
rbtreeNode* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
uncle->_col = rootp->_col = BLACK;
grandfather->_col = RED;
cur = rootp;
rootp = rootp->_parent;
if (rootp == _node)
break;
}
else
{
if (rootp->_right == rootp)
{
rotateL(grandfather);
grandfather->_col = RED;
rootp->_col = BLACK;
}
else
{
rotateR(rootp);
rotateL(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_node->_col = BLACK;
return true;
}
红黑树的验证
这里我们也是去写一个函数去判断是否为红黑树。
cpp
bool isrbtree()
{
return isrbtree(_node); //将判断函数封装起来
}
bool isrbtree(rbtreeNode*root)
{
if (root == nullptr)
{
return true;
}
int size = 0;
rbtreeNode* head = root;
while (head)
{
if (head->_col == BLACK)
size++;
head = head->_left; //找一个节点有多少个黑色节点,每条路径都有相同的黑色节点
}
if (_node->_col == RED)
{
cout << "根为红" << endl; //如果根节点吗为红色return false
return false;
}
return iscout(root,0,size);
}
bool iscout(rbtreeNode*root,int count,int N)
{
if (root == nullptr)
{
if (count == N) //判断每条路径的高是否相同。
return true;
else
{
cout << count << " " << N << endl;
cout << "高不同" << endl;
return false;
}
}
if (root->_col==BLACK)
{
count++;
}
rbtreeNode* rootp = root->_parent;
if (rootp&&rootp->_col==RED&&root->_col==RED)
{
cout << "有在一起的红节点" << endl; //判断是否有连在一起的红节点
return false;
}
return iscout(root->_left, count, N) && iscout(root->_right, count, N);
}