标签:log comment 不能 nts std south ring line ext
1.每个节点的颜色只能是黑色或者是红色
2.根节点是黑色的
3.如果一个节点的颜色是红色,则他的两个孩子都是黑的,也就是说一条路径上不能出现两个相邻的红色节点。
4.对每个节点来说 ,从该节点到其子孙叶子节点的所有路径上,黑色节点的个数相同。
5.每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
情形1:parent是grendParent的左孩子,并且uncle节点存在且为红色。
调整方式:将parent和uncle节点改为黑色,并将grendParent改为红色,然后继续向上调整。
Node *grandParent = parent->_pParent;
if (parent == grandParent->_pLeft)
{
Node *uncle = grandParent->_pRight;
if (uncle && RED == uncle->_color)
{
parent->_color = BLACK;
uncle->_color = BLACK;
grandParent->_color = RED;
pNew = grandParent;
parent = grandParent->_pParent;
}
情形2: parent是grendParent的左孩子,插入节点是parent的左孩子,并且uncle节点不存在或者为黑色。
调整方式:将parent与grandParent的颜色互换,并进行右旋。
情形3:parent是grendParent的左孩子,插入节点是parent的右孩子,并且uncle节点不存在或者为黑色。
调整方式:先进行左旋,再将parent与grandParent的颜色互换,并进行右旋。
else//uncle节点不存在或者为黑
{
if (pNew == parent->_pRight)
{
lRotate(parent);
std::swap(parent, pNew);
}
parent->_color = BLACK;
grandParent->_color = RED;
rRotate(grandParent);
}
情形4:parent是grendParent的右孩子,并且uncle节点存在且为红色。
调整方式:将parent和uncle节点改为黑色,并将grendParent改为红色,然后继续向上调整。
else//parent 为grandParent的右孩子
{
Node *uncle = grandParent->_pLeft;
if (uncle && RED == uncle->_color)
{
parent->_color = BLACK;
uncle->_color = BLACK;
grandParent->_color = RED;
pNew = grandParent;
parent = grandParent->_pParent;
}
情形5: parent是grendParent的做右孩子,插入节点是parent的右孩子,并且uncle节点不存在或者为黑色。
调整方式:将parent与grandParent的颜色互换,并进行左旋。
情形6:parent是grendParent的右孩子,插入节点是parent的左孩子,并且uncle节点不存在或者为黑色。
调整方式:先进行右旋,再将parent与grandParent的颜色互换,并进行左旋。
综上其实可以分为parent是grendParent的左孩子或者右孩子两大类,两种情况又分别有三种情况,所以完整的插入代码如下
bool Insert(const K &key, const V &value)
{
Node *pNew = new Node(key, value);
if (NULL == _pRoot)
{
_pRoot = pNew;
_pRoot->_color = BLACK;
return true;
}
//寻找插入位置
Node *parent = NULL;
Node *pCur = _pRoot;
while (pCur)
{
if (key < pCur->_key)
{
parent = pCur;
pCur = pCur->_pLeft;
}
else if (key > pCur->_key)
{
parent = pCur;
pCur = pCur->_pRight;
}
else
return false;
}
//插入节点
if (key < parent->_key)
parent->_pLeft = pNew;
else
parent->_pRight = pNew;
pNew->_pParent = parent;
//判断是否违反性质进行调整
while (parent && parent != _pRoot && RED == parent->_color)
{
Node *grandParent = parent->_pParent;
if (parent == grandParent->_pLeft)
{
Node *uncle = grandParent->_pRight;
if (uncle && RED == uncle->_color)
{
parent->_color = BLACK;
uncle->_color = BLACK;
grandParent->_color = RED;
pNew = grandParent;
parent = grandParent->_pParent;
}
else//uncle节点不存在或者为黑
{
if (pNew == parent->_pRight)
{
lRotate(parent);
std::swap(parent, pNew);
}
parent->_color = BLACK;
grandParent->_color = RED;
rRotate(grandParent);
}
}
else//parent 为grandParent的右孩子
{
Node *uncle = grandParent->_pLeft;
if (uncle && RED == uncle->_color)
{
parent->_color = BLACK;
uncle->_color = BLACK;
grandParent->_color = RED;
pNew = grandParent;
parent = grandParent->_pParent;
}
else//uncle节点不存在或者为黑
{
if (pNew == parent->_pLeft)
{
rRotate(parent);
std::swap(parent, pNew);
}
parent->_color = BLACK;
grandParent->_color = RED;
lRotate(grandParent);
}
}
}
_pRoot->_color = BLACK;
return true;
}
左旋及右旋代码
void lRotate(Node *parent)
{
Node *subR = parent->_pRight;
Node *subRL = subR->_pLeft;
parent->_pRight = subRL;
if (subRL)
subRL->_pParent = parent;
subR->_pLeft = parent;
Node *pparent = parent->_pParent;
parent->_pParent = subR;
subR->_pParent = pparent;
if (NULL == pparent)
{
_pRoot = subR;
}
else
{
if (pparent->_pLeft == parent)
pparent->_pLeft = subR;
else
pparent->_pRight = subR;
}
}
void rRotate(Node *parent)
{
Node *subL = parent->_pLeft;
Node *subLR = subL->_pRight;
parent->_pLeft = subLR;
if (subLR)
subLR->_pParent = parent;
subL->_pRight = parent;
Node *pparent = parent->_pParent;
parent->_pParent = subL;
subL->_pParent = pparent;
if (NULL == pparent)
{
_pRoot = subL;
}
else
{
if (pparent->_pLeft == parent)
pparent->_pLeft = subL;
else
pparent->_pRight = subL;
}
}
bool Test()
{
if (NULL == _pRoot)
return true;
if (BLACK != _pRoot->_color)
{
cout << "不满足性质1:根的颜色为黑色" << endl;
return false;
}
size_t numofBlackN = 0;
Node *pCur = _pRoot;
while (pCur)
{
if (BLACK == pCur->_color)
numofBlackN++;
pCur = pCur->_pLeft;//统计最左边分支的黑色节点个数。
}
return _test(_pRoot, numofBlackN, 0);
}
bool _test(Node *pRoot, size_t numofBlackN, size_t index)
{
if (NULL == pRoot)
return true;
if (RED == pRoot->_color)
{
if (pRoot->_pLeft && RED == pRoot->_pLeft->_color || pRoot->_pRight && RED == pRoot->_pRight->_color)
{
cout << "违反性质3:两个红色节点相邻" << endl;
return false;
}
}
if (BLACK == pRoot->_color)
index++;
if (NULL == pRoot->_pLeft && NULL == pRoot->_pRight)
{
if (numofBlackN != index)
{
cout << "违反性质4:每条路径黑色节点个数不相同" << endl;
return false;
}
}
return _test(pRoot->_pLeft, numofBlackN, index) && _test(pRoot->_pRight, numofBlackN, index);
}
上述代码只能测试是否满足红黑树的5个性质,红黑树也是一个二叉搜索树,我们要检验二叉搜索树的正确性,可以采用中序遍历,看看是否正确。
void inorder()
{
_inorder(_pRoot);
}
void _inorder(Node *pRoot)
{
if (NULL == pRoot)
return;
_inorder(pRoot->_pLeft);
cout << pRoot->_key << "->";
_inorder(pRoot->_pRight);
}
自此我们的红黑树插入操作就完成了。
标签:log comment 不能 nts std south ring line ext
原文地址:http://blog.csdn.net/jyy305/article/details/71636992