本人大四即将结束,于2018年12月18日购《算法导论》这本书,慢慢看,第一阶段先主要理解各个章节说的算法都是什么意思,书上的课后习题先不做,用得上什么算法我再详细学习。这是官方课后答案的链接。
放在开头:没有好的算法,坏的算法之说,重点是针对不同的情况,针对不同的数据,针对不同的需求,去选择算法,改良算法。我的数学功底不强,太难的公式我看不懂,太高深的思想我理解不了,我主要以应用为主,不以解释数学公式为主。
上一章介绍的二叉搜索树,时间复杂度均为O(h),这个红黑树(red-black tree),是众多平衡搜索树中的一种,可以保证在最坏的情况下基本动态集合操作的时间复杂度为O(lgn),岂不是更好。
红黑树的性质
它比上一章讲的二叉搜索树多了一种属性:color。
性质:
1、每个结点不是红色就是黑色
2、根结点是黑色
3、每个叶结点(NIL)是黑色的
4、如果一个结点是红色的,它的两个子结点都是黑色的
5、对于每个结点,从该结点到它的所有后代叶结点的路径上,均包含相同数目的黑色结点。
旋转(重点)
一会儿主要会介绍两种基本操作:插入和删除。但是这两个操作会对树做出修改,导致5种性质被破坏,我们必须要改变书中某些节点的颜色以及指针结构。
旋转操作,能保持二叉搜索树性质的局部操作,也是红黑树的一种特色操作。
旋转分左旋和右旋,下面这个图是左旋。
通俗点说:子结点变父结点,父结点变子结点。原来的子结点的左子结点变成新的子结点的右子结点。
同理:右旋就可以概括成,子结点变父结点,父结点变子结点。原来的子结点的右子结点变成新的子结点的左子结点。
插入
红黑树的插入比我们之前的二叉搜索树的插入,要复杂的很多。
设z是我们要插入的结点,我们的插入程序,只是对上一章的插入步骤做了少许处理:
1、所有的NIL都被T.nil代替,这是为了方便维护红黑树的性质
2、z插入后,它的color属性为红色(方便维护红黑树的性质)
3、在插入后,我们调用了一个RB-INSERT-FIXUP的程序,来保持红黑树的性质,因为我们新加了一个节点,难免会破坏部分性质。
下面重点说说这个RB-INSERT-FIXUP的这个程序。
程序的终止条件是z.p是黑色的。
我们加入一个红色节点后,可能破坏的性质有两个:
1、我们的z可能是根节点,根节点必须是黑色的。
2、我们的z.p是红色,性质4就被破坏了,因为我们规定,红结点的两个子结点必须是黑色的。
我们分3种情况讨论(其实一共是6种,3种是z.p是左孩子,3种z.p是右孩子,我们这里讨论一下z.p是左孩子)
情况1:z的叔结点是红色的
情况2:z的叔结点是黑色的且z是一个右孩子
情况3:z的叔结点是黑色的且z是一个左孩子(情况三是由情况二演化过来的)
书中具体讲解这几种情况的内容,有满满的3页,贼多,跟看史记一样。
我的总结:看RB-INSERT-FIXUP的时候,三种情况的大致思想是,抓住z.p.p是黑色的这个重点(如果是红色的,那z.p肯定是黑色的,早就结束循环了),将z,p,p的黑色的分解,将z.p,和z的叔结点变成黑色的,然后将z上移至z.p.p。
删除
这个情况分的比插入还复杂,RB-DELETE-FIXUP分了四种情况,太复杂了,我没找到什么规律,也没有发现什么新的东西,就先不分析了。