红黑树的插入总共不算镜像的话总共五种情况:
- 插入就要做根,即插入之前树中没有结点,插入的这个结点就是m_head的parent
- 第二种就是插入的父亲是黑的,所以不需要改变
- 第三种就是插入的父亲是红的,叔叔也是红的,此时需要的操作是改色,将父亲结点与叔叔结点的颜色变成黑的,将爷爷结点的颜色变成红色,然后继续向上遍历,将所有的出现的这种情况都处理了,如果遇到根就先变红再变黑,即遇到m_head就退出
- 第四种是父亲是红色,但是叔叔是黑的,我和父亲一条线,进行单旋,单旋结束后将父亲的额颜色变成黑色,爷爷的颜色变成红色
- 最后一种如果我父亲是红色,叔叔黑色,但是我和父亲不在一条线上没救需要根据情况进行双旋,第一次旋转之后交换一下我和父亲结点,然后就和第四种一样了,最后记得将爷爷变红,父亲变黑
bool insert(const T & val)
{
RBTreeNode<T> * & root = getRoot();
if (root)
{
RBTreeNode<T> * cur = root;
RBTreeNode<T> * pre = nullptr;
while (cur)
{
if (val < cur->m_data)
{
pre = cur;
cur = cur->m_left;
}
else if (val > cur->m_data)
{
pre = cur;
cur = cur->m_right;
}
else
{
return false;
}
}
//上面的代码完成的是查找要插入的点的位置
cur = new RBTreeNode<T>(val);
if (val < pre->m_data)
{
pre->m_left = cur;
}
else
{
pre->m_right = cur;
}
cur->m_parent = pre;
//上面的代码完成的是将要插入的点在pre的左边还是右边确定下来
if (pre->m_color == RED)
{
RBTreeNode<T> * grand = pre->m_parent;
RBTreeNode<T> * uncle;
if (pre == grand->m_left)
{
while (pre != m_head && pre->m_color == RED)
{
grand = pre->m_parent;
uncle = grand->m_right;
if (uncle && uncle->m_color == RED)//第三种情况
{
pre->m_color = BLACK;
uncle->m_color = BLACK;
grand->m_color = RED;
cur = grand;
pre = cur->m_parent;
}
else
{
if (cur == pre->m_right)
{
lRound(pre);
RBTreeNode<T> * tmp;
tmp = pre;
pre = cur;
cur = tmp;
}
rRound(grand);
pre->m_color = BLACK;
grand->m_color = RED;
break;
}
}
}
else
{
while (pre != m_head && pre->m_color == RED)
{
grand = pre->m_parent;
uncle = grand->m_left;
if (uncle && uncle->m_color == RED)//第三种情况
{
pre->m_color = BLACK;
uncle->m_color = BLACK;
grand->m_color = RED;
cur = grand;
pre = cur->m_parent;
}
else
{
if (cur == pre->m_left)
{
rRound(pre);
RBTreeNode<T> * tmp;
tmp = pre;
pre = cur;
cur = tmp;
}
lRound(grand);
pre->m_color = BLACK;
grand->m_color = RED;
break;
}
}
}
}
//省略的else是第二种情况
}
else//第一种情况
{
root = new RBTreeNode<T>(val, BLACK);
root->m_parent = m_head;
m_head->m_parent = root;
}
root->m_color = BLACK;
m_head->m_left = leftMost();
m_head->m_right = rightMost();
return true;
}