看了很多资料,网上讲红黑树插入删除讲得实在太乱了,没有统一的步骤,让初学者容易混乱。这里我整理下,左旋右旋就不详解了。直接看插入删除的具体操作。
我就不画图了,借助https://www.cs.usfca.edu/~galles/visualization/RedBlack.html来直接截图给大家演示
1.插入
插入的节点默认是红节点
1.1 找到插入的位置,将该节点插入,若该节点的父节点为黑,红黑树性质继续保持,操作完成。
1.2 若父节点为红色,则红黑树性质被破坏,需要进行调整。
case 1:当叔父节点为红时(插入节点为6,叔父节点为9)
=》 =》
处理方法:将父结点和叔父结点变为黑色,祖父结点变为红色。将祖父结点作为新插入的结点继续向上迭代进行平衡操作,在迭代时如果调整到根,则根为黑色,跳出循环(否则继续循环,循环结束条件为当前节点的父节点颜色为黑色),调整完毕。
case 2:叔父节点为黑,插入节点,父亲节点,祖父节点三者不在一条直线上(插入节点为24,叔父节点为黑色(空叶子节点为黑色))
=》
处理方法:以父亲节点右旋(若插入节点是父亲节点的右儿子则左旋),将父亲节点看为新的插入节点(即图中的插入节点变为22),将情况转化为case3,交给case 3处理。
case 3:叔父节点为黑,插入节点,父亲节点,祖父节点三者在一条直线上(插入节点黑21,叔父节点为黑色(空叶子节点为黑色))
=》
处理方法:交换父亲节点和祖父节点的颜色,然和以祖父节点右旋(如若这根直线是斜向下的则进行左旋操作),则调整结束。
插入调整总结起来就这三种情况,下面给出插入调整的golang代码。
func (rbt *RBTree) insertBalanceFixup(insertnode *TreeNode) {
var uncle *TreeNode
for insertnode.parent.color == "red" {
grandfather := insertnode.parent.parent //父节点为红,肯定不为根节点,则存在祖父节点
if insertnode.parent == grandfather.lchild {
uncle = grandfather.rchild
} else {
uncle = grandfather.lchild
}
if uncle.color == "red" { //case 1
uncle.color, insertnode.parent.color = "black", "black"
insertnode = grandfather
if insertnode == rbt.root {
return
}
grandfather.color = "red"
continue
}
//叔叔为黑
parent := insertnode.parent
if parent == grandfather.lchild { //父亲为左儿子
if insertnode == parent.rchild { //case2
insertnode = parent
rbt.LeftRotate(insertnode)
}
insertnode = insertnode.parent //case3
insertnode.color = "black"
insertnode = insertnode.parent
insertnode.color = "red"
rbt.RightRotate(insertnode)
} else { //父亲为右儿子
if insertnode == parent.lchild { //case2
insertnode = parent
rbt.RightRotate(insertnode)
}
insertnode = insertnode.parent //case3
insertnode.color = "black"
insertnode = insertnode.parent
insertnode.color = "red"
rbt.LeftRotate(insertnode)
}
return
}
}