对红黑树的理解【增加节点篇】

来源:互联网 发布:淘宝店运营计划书 编辑:程序博客网 时间:2024/04/30 15:17

    红黑树属于二叉树。

    首先说说二叉树的优点,二叉树的左孩子比自己小,右孩子比自己大,这样在进行查找的时候,就可以像二分查找一样每一次都可以缩小要查找的值的范围。

    如果这个二叉树是平衡二叉树的话,查找的速度可以想象(因为不需要遍历所有的节点)。

    但是,相反考虑,如果这个二叉树退化成了链表,这样就会出现最糟糕的行为(因为对于链表的查找就是需要一个个进行遍历,而且链表本身还占用了更多内存)。

    红黑树就属于变种的二叉树,他的目的是为了让二叉树尽可能平衡,并且新增和删除时尽可能不做更多的操作,在平均使用的情况下显现出良好的性能。

    那红黑树是怎么做到让二叉树尽可能平衡的呢?

    红黑树规定了:

    1.首先红黑树属于二叉树(这不是废话蛮)。

    2.红黑树的节点非红即黑。每加入一个节点,需要给节点涂上颜色。

    3.根节点必须是黑色。

    4.不能有连续的两个红节点(即红节点的儿子和父亲都必须为黑)。

    5.从根节点到叶节点的每一条路径上的黑节点数量相同。

    第四条规则和第五条规则是保证红黑树平衡最重要的规定。第四条规则很好理解,第五条规则是什么意思是呢?


    ABD,ABE,AC这三条路径中,黑色节点的和都是2,即满足第五条规定。

    那么,现在让我们来谈谈红黑树的增加和删除(查找和二叉树的查找一样,就不详细描述了)。

    红黑树的增加:

    其实红黑树的增加所做的一些操作,都是为了使得新增的节点都是红色。就上图的情况来说,如果新增的节点比D的值要小,那就会成为D的左孩子,要满足红黑树的规定,新增加的孩子颜色就需要变成红(给黑色节点添加儿子节点的操作是最简便的)。

    

    但是实际上,有些情况可能是,新增加的节点的父亲为红色,而红黑树规定不能有连续的两个红色节点,那这时候,就需要用到AVL的旋转,再配以适当的更改节点的颜色了。

    这里要分两种情况。

    第一,当父亲节点的兄弟节点为黑色或者父亲节点没有兄弟节点时。(这里是上图的一部分)

    

    如图,新增加的节点为G,父亲为红色的F,父亲的兄弟节点没有,这时就满足第一个情况。

    这时候,因为G是F的左孩子,所以对F做左单旋转(旋转的知识可查看AVL树)。

    

    然后更改节点的颜色:

    

    为什么旋转之后就能满足红黑树的规定了呢?

    首先,规定4肯定满足了,最麻烦的是规定5,从根节点到叶节点的每一条路径上的黑节点数量相同。

    旋转之前,DF路径上只有一个黑色,加上G,G肯定要是黑色,这是DFG路径就有两个黑色,这样的话ABDFG就是3个黑色节点,而AC,ABE路径只有两个黑色节点,违反规定5。

     而旋转之后,F成为了原来的D,G成为了原来的F,原来DF路径现在成为了FG路径。即:

    

    旋转就是为了让原来的ABDF路径上少一个黑色,让这个黑色成为ABFG,ABFD公共的黑色,这样每条路径上的黑色节点数量就想等了。


   第二种情况多少要复杂一点:

    当父亲节点的兄弟节点为红色时(接着上图):

    如果新增了一个节点H,H比G小,成为了G的左孩子,而G的兄弟节点D也是红色

    

   这时候就不能想第一种情况来处理(详细可以自己试试,发现肯定会失败的)。

    记住,增加节点的时候,都是想方设法的让新增加的节点都是为红色,父亲节点为黑色。

   那么,这里就要对FDG进行颜色更换了。

   即,F变为红色,GD变为黑色,那么,H就可以顺理成章的成为黑色节点G的左孩子了。

    

    但是,这里又出现问题了,连续的两个BF节点,违反了规定4,那么,不要着急,我们之前做的都没错,这时候,就吧F想象成新插入的节点,B当做父亲节点来处理,这时候发现父亲节点B的兄弟节点为C,是黑色的,就回到了第一种情况了。

   

    这样,节点就插入成功了。

    是不是发现,节点的插入会导致红黑树是相对比较平衡的呢?在实际生产环境中,红黑树的平衡性能确实要比一般的二叉树要好,而相对于AVL为平衡做巨多的操作,红黑树的操作就相对少了很多。

    

    

    

0 0