<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>join (李亚夫)</title>
    <link>https://ruby-china.org/join</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>理解红黑树</title>
      <description>&lt;p&gt;本文 blog 链接
&lt;a href="http://www.leyafo.com/post/2014-10-27-a-red-black-tree-implementation/" rel="nofollow" target="_blank"&gt;http://www.leyafo.com/post/2014-10-27-a-red-black-tree-implementation/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;红黑树是有序平衡 BST(binary search tree) 的一种，它于 1978 年由 Guibas 和 Sedgewick 发明。红黑树是&lt;a href="http://en.wikipedia.org/wiki/2%E2%80%933%E2%80%934_tree" rel="nofollow" target="_blank" title=""&gt;2-3-4 树&lt;/a&gt; 的一种抽象表示。有趣的是现在大多数算法书关于红黑树都没有提到过 2-3-4 树。算法书上关于红黑树的讲解都是基于定理来实现红黑树。至于这些定理怎么来的，算法书却没有描述过。这就是为啥算法书上的红黑树难以理解，这是算法书的坑。所以要理解红黑树，理解 2-3-4 树 是必不可少的一个过程。&lt;/p&gt;
&lt;h2 id="2-3-4树"&gt;2-3-4 树&lt;/h2&gt;&lt;h3 id="2-3-4树的基本性质"&gt;2-3-4 树的基本性质&lt;/h3&gt;
&lt;p&gt;2-3-4 树也是一种有序的平衡树，所有从 leaf 到 root 的 path 的高度都是相等的。每个节点可以容纳 1 到 3 个节点，可以有 2 到 4 个子节点。下面就是 2-3-4 树的 3 种类型。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="no"&gt;B&lt;/span&gt;               &lt;span class="no"&gt;D&lt;/span&gt;   &lt;span class="no"&gt;F&lt;/span&gt;                &lt;span class="no"&gt;H&lt;/span&gt;   &lt;span class="no"&gt;K&lt;/span&gt;   &lt;span class="no"&gt;O&lt;/span&gt;  
 &lt;span class="sr"&gt;/ \             /&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="p"&gt;\&lt;/span&gt;              &lt;span class="sr"&gt;/ \ /&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt; &lt;span class="sr"&gt;/ \  
A   C           B   E   G            A   I   L   Y  
 2树                3树                    4树
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类似于 BST，2-3-4 对元素的排序是左小右大。不同的 3 树和 4 树的子节点会有中间大小的子节点。比如上图的 3 树中的 E 就比 D 大 比 F 小。4 树中的 I 比 H 大，比 K 小。L 比 K 大，比 O 小。&lt;/p&gt;
&lt;h3 id="2-3-4树的插入"&gt;2-3-4 树的插入&lt;/h3&gt;
&lt;p&gt;前面说了 2-3-4 树是一种平横树，所有从 leaf 到 root 的 path 的高度都是相等的。这也就意味着每当插入一个新节点不能单纯的像 BST 那样将新的节点插入到树的底部，否则会破坏树的平衡。2-3-4 树使用的平衡方法是合并。就是将 2 树变为 3 树，3 树变 4 树。如下图：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;   &lt;span class="no"&gt;B&lt;/span&gt;                         &lt;span class="no"&gt;B&lt;/span&gt;
  &lt;span class="sr"&gt;/ \        插入 D =&amp;gt;       /&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
 &lt;span class="no"&gt;A&lt;/span&gt;   &lt;span class="no"&gt;C&lt;/span&gt;                     &lt;span class="no"&gt;A&lt;/span&gt;  &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;D&lt;/span&gt;  

  &lt;span class="no"&gt;B&lt;/span&gt;                            &lt;span class="no"&gt;B&lt;/span&gt;
 &lt;span class="sr"&gt;/ \          插入 H=&amp;gt;        /&lt;/span&gt;   &lt;span class="p"&gt;\&lt;/span&gt;
&lt;span class="no"&gt;A&lt;/span&gt;  &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;D&lt;/span&gt;                      &lt;span class="no"&gt;A&lt;/span&gt;   &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;D&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的插入方法解决了往 2-3-4 树 插入新节点而不破坏树的平衡的问题。但是如果要插入的节点已经是一个 4 树了，这种方法就不管用了，因为 4 树是没法变为 5 树的。可以将 4 树往上挪一个节点，并分裂出俩个 2 树的子节点。如果上面的父节点已经是 4 树了，则继续往上挪动。直到 root 节点，再需要分裂的话，这个时候可以将 root 节点也进行分裂。root 节点分裂后整颗树的高度会增加一层。如下图所示：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="no"&gt;A&lt;/span&gt;                  &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;S&lt;/span&gt;                      &lt;span class="no"&gt;A&lt;/span&gt;   &lt;span class="no"&gt;E&lt;/span&gt;   &lt;span class="no"&gt;S&lt;/span&gt;          
 &lt;span class="sr"&gt;/ \     插入 S=&amp;gt;    /&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;         &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;插入&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt;   &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt; &lt;span class="sr"&gt;/ \ /&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;插入&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt; &lt;span class="o"&gt;----&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;先将&lt;/span&gt; &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="no"&gt;S&lt;/span&gt; &lt;span class="n"&gt;往上分裂&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;      &lt;span class="no"&gt;E&lt;/span&gt;                                &lt;span class="no"&gt;E&lt;/span&gt;
                          &lt;span class="sr"&gt;/  \          插入 R=&amp;gt;           /&lt;/span&gt;  &lt;span class="p"&gt;\&lt;/span&gt;
                         &lt;span class="no"&gt;A&lt;/span&gt;    &lt;span class="no"&gt;S&lt;/span&gt;                          &lt;span class="no"&gt;A&lt;/span&gt;   &lt;span class="no"&gt;R&lt;/span&gt; &lt;span class="no"&gt;S&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="2-3-4树的删除"&gt;2-3-4 树的删除&lt;/h3&gt;
&lt;p&gt;树结构的删除都很麻烦，2-3-4 树 也不例外。2-3-4 树 插入的时候需要保持树的平衡，删除的时候也需要保持树的平衡。如果需要降低树的高度从 root 合并来降低树的高度。2-3-4 树 和 BST 一样会选择从 leaf 节点将 node 删除。如果找到的节点不是 leaf 节点会从当前节点的右边出发，找到最左边的 leaf 节点来替换，然后删除被替换后的 leaf 节点。如果 leaf 节点是 3 树或者或者 4 树，直接删除即可。如果是 2 树的话就不能直接删除，需要对其进行旋转操作，从临近的同一层节点挪个节点过来补上。如果临近元素也是 2 树则从父节点挪一个节点下来。
下图是删除 3 树和 4 树的情况：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="no"&gt;C&lt;/span&gt;                   &lt;span class="no"&gt;C&lt;/span&gt;                    &lt;span class="no"&gt;D&lt;/span&gt;                  &lt;span class="no"&gt;D&lt;/span&gt;
 &lt;span class="sr"&gt;/     删除 B=&amp;gt;       /&lt;/span&gt;                    &lt;span class="o"&gt;/&lt;/span&gt;       &lt;span class="n"&gt;删除&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="sr"&gt;/
AB                  A                    ABC                 AC
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下图是一个比较复杂的删除操作，删除一个非叶子节点，会碰到 2 树的删除并需要旋转的情况。(节点比较多所以用数字来表示节点)&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;            &lt;span class="mi"&gt;40&lt;/span&gt;
       &lt;span class="sr"&gt;/         \
     20           50                     删除根节点40
    /&lt;/span&gt;  &lt;span class="p"&gt;\&lt;/span&gt;       &lt;span class="sr"&gt;/     \                   找到右树最左边的42节点 -----------&amp;gt;
  14   32     43     62 70 79            并替换掉,再删除替换后的叶子节点
  /&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;   &lt;span class="sr"&gt;/\     /&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;     &lt;span class="sr"&gt;/ |  | \
10 18 25 33  42 47  57 65 74 81

              42
         /&lt;/span&gt;         &lt;span class="p"&gt;\&lt;/span&gt;                       
      &lt;span class="n"&gt;左树不变&lt;/span&gt;        &lt;span class="mi"&gt;50&lt;/span&gt;                    
                   &lt;span class="sr"&gt;/    \                  相邻节点也是2树，将43挪下来并合并 ------&amp;gt;
                43     62 70 79            
               /&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;     &lt;span class="sr"&gt;/ |  | \             
              x  47   57 65 74 81


              42
           /&lt;/span&gt;      &lt;span class="p"&gt;\&lt;/span&gt;
       &lt;span class="n"&gt;左树不变&lt;/span&gt;      &lt;span class="mi"&gt;50&lt;/span&gt;
                  &lt;span class="sr"&gt;/    \ 
               43 47  62 70 79           上一步中43也是2树
                      /&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;           &lt;span class="n"&gt;需要从临近的节点通过旋转来拿到一个节点&lt;/span&gt;  &lt;span class="o"&gt;-----&amp;gt;&lt;/span&gt;
                    &lt;span class="mi"&gt;57&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt;  &lt;span class="mi"&gt;74&lt;/span&gt; &lt;span class="mi"&gt;81&lt;/span&gt;


                  &lt;span class="mi"&gt;42&lt;/span&gt;
               &lt;span class="sr"&gt;/      \
           左树不变      62             &amp;lt;----- 62旋转上来
                      /&lt;/span&gt;    &lt;span class="p"&gt;\&lt;/span&gt; 
                    &lt;span class="mi"&gt;50&lt;/span&gt;     &lt;span class="mi"&gt;70&lt;/span&gt; &lt;span class="mi"&gt;79&lt;/span&gt;
                  &lt;span class="sr"&gt;/   \    /&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="p"&gt;\&lt;/span&gt;
               &lt;span class="mi"&gt;43&lt;/span&gt; &lt;span class="mi"&gt;47&lt;/span&gt;  &lt;span class="mi"&gt;57&lt;/span&gt;  &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="mi"&gt;74&lt;/span&gt; &lt;span class="mi"&gt;81&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;-----------&lt;/span&gt; &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="n"&gt;变为50的子节点&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="红黑树"&gt;红黑树&lt;/h2&gt;
&lt;p&gt;红黑树是 2-3-4 树的一种抽象表示，在 1978 年 Guibas 和 Sedgewick 发明最初的红黑树。2008 年 Sedgewick 对其进行了改进，并将此命名为 LLRBT(Left-leaning red–black tree 左倾红黑树)。LLRBT 相比 1978 年的红黑树要简单很多，实现的代码量也少很多。Sedgewick 的一篇 &lt;a href="http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf" rel="nofollow" target="_blank" title=""&gt;PPT&lt;/a&gt; 对此有非常详细的介绍。现在大部分工程中的红黑树都是基于 1978 发明的算法，本文介绍的是 LLRBT。&lt;/p&gt;
&lt;h3 id="红黑树的抽象表示"&gt;红黑树的抽象表示&lt;/h3&gt;
&lt;p&gt;在红黑树中表示 2-3-4 树的 3 树和 4 树会用红链接来表示。如下图所示 (markdown 没有文本色彩支持，本文用//或\\来表示红色链接)：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt; &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt;                   &lt;span class="no"&gt;B&lt;/span&gt;             &lt;span class="no"&gt;A&lt;/span&gt;             &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt;                       &lt;span class="no"&gt;B&lt;/span&gt;
&lt;span class="sr"&gt;/ | \  &amp;lt;=红黑树表示=&amp;gt;  /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;    &lt;span class="n"&gt;或者&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;    &lt;span class="p"&gt;\\&lt;/span&gt;          &lt;span class="sr"&gt;/ | | \    &amp;lt;=红黑树表示=&amp;gt;  /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;  &lt;span class="p"&gt;\\&lt;/span&gt;
                    &lt;span class="no"&gt;A&lt;/span&gt;                  &lt;span class="no"&gt;B&lt;/span&gt;                                  &lt;span class="no"&gt;A&lt;/span&gt;      &lt;span class="no"&gt;C&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="红黑树的插入"&gt;红黑树的插入&lt;/h3&gt;
&lt;p&gt;红黑树在插入时也通过旋转来降低或者升高树的高度 (关于旋转请看我的&lt;a href="http://leyafo.logdown.com/posts/178297-avl-tree-implementation" rel="nofollow" target="_blank" title=""&gt;另一篇文章&lt;/a&gt;)。不同的是红黑树插入节点的方式是按照 2-3-4 树插入节点的方式来进行的。2-3-4 树每插入一个节点会对树自底向上进行调整 (合并或分裂)，红黑树也是对应于 2-3-4 树进行同样的操作。2-3-4 树通过将 3 树合并为 4 树，4 树分裂为俩个 2 树。红黑树通过旋转来做这些操作。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;在2树中插入一个节点&lt;/span&gt;&lt;span class="err"&gt;：&lt;/span&gt;
  &lt;span class="no"&gt;D&lt;/span&gt;  &lt;span class="n"&gt;插入C&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;    &lt;span class="no"&gt;D&lt;/span&gt;
              &lt;span class="sr"&gt;//&lt;/span&gt;
             &lt;span class="no"&gt;C&lt;/span&gt;                                                         
                                                &lt;span class="o"&gt;&amp;lt;===&lt;/span&gt;&lt;span class="n"&gt;等同于3树&lt;/span&gt;&lt;span class="o"&gt;===&amp;gt;&lt;/span&gt;    &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;D&lt;/span&gt;
                &lt;span class="no"&gt;C&lt;/span&gt;                       &lt;span class="no"&gt;D&lt;/span&gt;                          &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
  &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="n"&gt;插入D&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;       &lt;span class="p"&gt;\\&lt;/span&gt;          &lt;span class="n"&gt;左旋&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="sr"&gt;//&lt;/span&gt;
                   &lt;span class="no"&gt;D&lt;/span&gt;                &lt;span class="no"&gt;C&lt;/span&gt;


 &lt;span class="n"&gt;在3树中插入一个节点&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  

  &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;                    &lt;span class="no"&gt;H&lt;/span&gt;             &lt;span class="no"&gt;H&lt;/span&gt; 
 &lt;span class="sr"&gt;/ | \      红黑树表示=&amp;gt; //            /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;             &lt;span class="no"&gt;C&lt;/span&gt;                         &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;
                      &lt;span class="no"&gt;C&lt;/span&gt;   &lt;span class="n"&gt;插入&lt;/span&gt; &lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="no"&gt;C&lt;/span&gt;      &lt;span class="n"&gt;右旋&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;       &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;树表示&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="sr"&gt;/ | | \
                                   /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;             &lt;span class="no"&gt;A&lt;/span&gt;    &lt;span class="no"&gt;H&lt;/span&gt;
                                  &lt;span class="no"&gt;A&lt;/span&gt;

                      &lt;span class="no"&gt;H&lt;/span&gt;              &lt;span class="no"&gt;H&lt;/span&gt;              &lt;span class="no"&gt;H&lt;/span&gt;           
 &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;     &lt;span class="n"&gt;红黑树表示&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;             &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="sr"&gt;/             /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;             &lt;span class="no"&gt;C&lt;/span&gt;                  &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;
&lt;span class="sr"&gt;/ | \              A    插入 C=&amp;gt;    A    左旋=&amp;gt;    A     右旋=&amp;gt;  /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;  &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;树表示&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sr"&gt;/ | | \
                                    \\          /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;            &lt;span class="no"&gt;A&lt;/span&gt;    &lt;span class="no"&gt;H&lt;/span&gt;              
                                      &lt;span class="no"&gt;C&lt;/span&gt;        &lt;span class="no"&gt;C&lt;/span&gt;          


 &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt;                    &lt;span class="no"&gt;C&lt;/span&gt;             &lt;span class="no"&gt;C&lt;/span&gt;
&lt;span class="sr"&gt;/ | \      红黑树表示=&amp;gt; /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;            &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;                                &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;
                     &lt;span class="no"&gt;A&lt;/span&gt;   &lt;span class="n"&gt;插入&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="no"&gt;A&lt;/span&gt;     &lt;span class="no"&gt;H&lt;/span&gt;               &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;树表示&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="sr"&gt;/ | | \
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从上图可以看出，LLRBT 之所以使用左倾 (left-leaning) 是为了将 3 树限制为一种，以便更容易的将 3 树转为 4 树，来减少实现上复杂度。下图是 4 节点的分裂。  &lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;
                                                    &lt;span class="sr"&gt;/                  /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
 &lt;span class="no"&gt;A&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;     &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;树分裂为俩个2树&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="no"&gt;C&lt;/span&gt;                      &lt;span class="no"&gt;C&lt;/span&gt;                 &lt;span class="no"&gt;C&lt;/span&gt;
&lt;span class="sr"&gt;/ | | \                     /&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;      &lt;span class="n"&gt;红黑树表示&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;      &lt;span class="n"&gt;分裂&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="sr"&gt;/ \     &amp;lt;---将红链提上去
                           A   H                 A    H             A  H  
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;红黑树在最初插入时使用的方式和普通的二叉树一样，递归查找到树的底部，然后将新节点插入到树的底部。在递归往回弹的时候对整颗树进行旋转调整，和 2-3-4 树使用相同的方式（3 树变 4 树，4 树分裂成俩个 2 树）来调整整颗树的高度。&lt;/p&gt;
&lt;h3 id="红黑树的删除"&gt;红黑树的删除&lt;/h3&gt;
&lt;p&gt;红黑树的删除方法非常复杂。删除任意一个节点，红黑树会像 BST 一样会从右树的最左边找到一个节点进行替换并删除。所以实现红黑树的关键一点就是要实现 DeleteMin 方法。LLRBT  结构是没有 parent 节点的，在删除一个节点是并不能像 AVL 树那样在删除后再旋转。LLRBT 在查找要删除的节点时就会对树进行调整，它会将要删除节点的那个方向的树通过旋转将树的高度升高一层。&lt;br&gt;
下图是在 DeleteMin 方法中将树的左边升高一层&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;      &lt;span class="sr"&gt;//&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;----&lt;/span&gt;&lt;span class="n"&gt;因为树是向左边递归的&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;           &lt;span class="o"&gt;/&lt;/span&gt;
     &lt;span class="no"&gt;H&lt;/span&gt;              &lt;span class="n"&gt;所以到&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt; &lt;span class="n"&gt;的链都是红的&lt;/span&gt;           &lt;span class="no"&gt;H&lt;/span&gt;
    &lt;span class="sr"&gt;/ \                                        /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;
   &lt;span class="no"&gt;C&lt;/span&gt;   &lt;span class="no"&gt;S&lt;/span&gt;          &lt;span class="n"&gt;颜色反转&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;将红色向下传&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;        &lt;span class="no"&gt;C&lt;/span&gt;    &lt;span class="no"&gt;S&lt;/span&gt;     
  &lt;span class="sr"&gt;/                                          /&lt;/span&gt;
 &lt;span class="no"&gt;B&lt;/span&gt;                                          &lt;span class="no"&gt;B&lt;/span&gt;

&lt;span class="n"&gt;这时如果&lt;/span&gt; &lt;span class="no"&gt;S&lt;/span&gt; &lt;span class="n"&gt;节点的left为红色&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;需要对其再做两次旋转&lt;/span&gt;
       &lt;span class="sr"&gt;/                          /&lt;/span&gt;                        &lt;span class="o"&gt;/&lt;/span&gt;
      &lt;span class="no"&gt;H&lt;/span&gt;                          &lt;span class="no"&gt;H&lt;/span&gt;                        &lt;span class="no"&gt;P&lt;/span&gt;
    &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;                      &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;                    &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt;
   &lt;span class="no"&gt;C&lt;/span&gt;    &lt;span class="no"&gt;S&lt;/span&gt;       &lt;span class="n"&gt;右旋S&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;        &lt;span class="no"&gt;C&lt;/span&gt;    &lt;span class="no"&gt;P&lt;/span&gt;         &lt;span class="n"&gt;左旋&lt;/span&gt; &lt;span class="no"&gt;H&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;   &lt;span class="no"&gt;H&lt;/span&gt;    &lt;span class="no"&gt;S&lt;/span&gt;      
  &lt;span class="sr"&gt;/    //                    /&lt;/span&gt;      &lt;span class="p"&gt;\\&lt;/span&gt;                &lt;span class="sr"&gt;//&lt;/span&gt;  
 &lt;span class="no"&gt;B&lt;/span&gt;    &lt;span class="no"&gt;P&lt;/span&gt;                     &lt;span class="no"&gt;B&lt;/span&gt;         &lt;span class="no"&gt;S&lt;/span&gt;              &lt;span class="no"&gt;C&lt;/span&gt;
                                                    &lt;span class="sr"&gt;/
                                                   B

                                                  /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
        &lt;span class="n"&gt;再将颜色反转回来&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;                          &lt;span class="no"&gt;P&lt;/span&gt;
                                                &lt;span class="sr"&gt;/ \
                                               H   S
                                             /&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
                                            &lt;span class="no"&gt;C&lt;/span&gt;
                                           &lt;span class="sr"&gt;/
                                          B                                               
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面做的这些操作的最终目的就是将树的最底部要删除的节点变为红色，这样是为了在删除的时候避免要删除的节点为 2 树。因为删除 3 树中的一个节点是不需要做其他转换可以直接删除的。在删除后需要重新自底向上修复整颗树的平衡。这样的删除方式看起来非常慢，实际上确实&lt;a href="http://www.read.seas.harvard.edu/~kohler/notes/llrb.html" rel="nofollow" target="_blank" title=""&gt;非常慢&lt;/a&gt;。即使在没有找到要删除的节点也会递归进行旋转 - 修复这一过程。另外这里的删除使用的抽象方式并不是 2-3-4 树的删除方式，实际上使用的是 2-3 树的抽象方式。在红树向下传递的过程中最终的叶子会是颗 3 树，而不会是 4 树。Sedgewick 的 PPT 里面并没有说到这个问题。他的&lt;a href="http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf" rel="nofollow" target="_blank" title=""&gt;另一篇论文&lt;/a&gt;才说到了这个问题。&lt;/p&gt;

&lt;p&gt;PS：
本人实现的 &lt;a href="https://github.com/leyafo/practice-algorithm/blob/master/DataStruct/rb_tree.c" rel="nofollow" target="_blank" title=""&gt;Red Black Tree&lt;/a&gt;。
Sedgewick 的 &lt;a href="http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf" rel="nofollow" target="_blank" title=""&gt;PPT&lt;/a&gt; 里面有两个错误.
    1. 在 deleteMax 方法中向下递归是 deleteMax(h.left) 应该是 deleteMax(h.right)。
    2. 在 delete 方法中需要添加当前节点是否为空的判断，否则递归到空节点时程序会挂掉。&lt;/p&gt;</description>
      <author>join</author>
      <pubDate>Wed, 05 Nov 2014 12:54:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/22499</link>
      <guid>https://ruby-china.org/topics/22499</guid>
    </item>
    <item>
      <title>rails 的前后端交互的问题</title>
      <description>&lt;p&gt;最近尝试着自己做了点东西，碰到点问题感觉有点卡壳了。&lt;/p&gt;

&lt;p&gt;我有一个基本的前端 html 页面，我在里面用 jquery 写了如下代码：&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;var div = $("div[align=middle]");
div.append('&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/event/new"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"event"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/form&amp;gt;&lt;/span&gt;');
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我在 routes 里面添加了如下代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s2"&gt;"/event/new"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"events#new_event"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个 events 是一个 controller，然后我在 controller 里面添加了 new_event 方法.
现在的问题是我需要拿上面那个 form 里面的数据和那个页面中的一些 javascript 变量值。我该如何拿？&lt;/p&gt;

&lt;p&gt;还有就是我发现大部分 rails 书籍侧重点都是在后端教你搭建一个基本的 CRUD 网站.
前端的东西基本上很少说，但到我自己真正做一个小东西的时候才发现前端这一块有点棘手。不知道怎么和后端连接起来.不知道大家有啥这方面好的资料推荐？&lt;/p&gt;</description>
      <author>join</author>
      <pubDate>Mon, 02 Dec 2013 17:15:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/15942</link>
      <guid>https://ruby-china.org/topics/15942</guid>
    </item>
    <item>
      <title>3 年 c/c++ 经验想转 ruby,请大家帮忙指点.</title>
      <description>&lt;p&gt;3 年的 c/c++ 开发，我做的项目一直是跟政府有关的，我厌倦了帮政府去开发软件，并且我再也不想做想关的软件了。之所以转 web 是因为我觉得 web 是用户最近的产品开发。我想做点能让用户用得爽的产品。&lt;br&gt;
我一直想玩玩函数式语言，但 lisp,Scheme 一些语言过于小众。单纯的新手很难应用到项目中去.毕竟我不是 Paul Graham.Ruby 是最接近这方面的 web 开发语言了。&lt;/p&gt;

&lt;p&gt;最近也打算裸辞了，专心学几个月 ruby 开发.
所以想让大家帮忙指点一些问题:
1.以我现在的状况学 ruby 会碰到什么问题？
2.你们在学习过程中碰到过哪些坑？如何努力去避免？
3.我对 web 开发完全陌生，这会对学习 rails 产生哪些影响？
4.我非常熟悉 C 语言，这会对我学习 web 开发带来哪些好处？&lt;/p&gt;

&lt;p&gt;至于适合不适合转型的问题，我觉得在我未完全学习和尝试的情况下这个问题是暂时还不存在的。&lt;/p&gt;</description>
      <author>join</author>
      <pubDate>Sat, 24 Aug 2013 11:15:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/13572</link>
      <guid>https://ruby-china.org/topics/13572</guid>
    </item>
  </channel>
</rss>
