Левосторонние красно-чёрные деревья — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Вращения)
м (rollbackEdits.php mass rollback)
 
(не показаны 194 промежуточные версии 6 участников)
Строка 1: Строка 1:
 
{{Определение
 
{{Определение
|definition =  Left-leaning Red-Black Trees{{---}} .  
+
|definition =  Левостороннее красно-черное дерево {{---}} тип сбалансированного двоичного дерева поиска, гарантирующий такую же асимптотическую сложность операций, как у красно-черного дерева поиска.
 
   }}
 
   }}
 +
 +
==Свойства==
 +
*Корневой узел всегда черный.
 +
*Каждый новый узел всегда окрашен в красный цвет.
 +
*Каждый дочерний нулевой узел листа дерева считается черным.
 +
 
==Вращения==
 
==Вращения==
One way to view red-black BST algorithms is as maintaining the following invariant properties under insertion and deletion:
+
Чтобы поддерживать левосторонние красно-черные двоичные деревья поиска необходимо соблюдать следующие инварианты при вставке и удалении:
• No path from the root to the bottom contains two consecutive red links.
+
* Ни один путь от корня до листьев дерева не содержит двух последовательных красных узлов.
• The number of black links on every such path is the same.
+
* Количество черных узлов на каждом таком пути одинаково.
These invariants imply that the length of every path in a red-black tree with N nodes is no longer than 2 lg N . This worst case is realized, for example, in a tree whose nodes are all black except for
 
those along a single path of alter- nating red and black nodes.
 
The basic operations that bal- anced-tree algorithms use to main- tain balance under insertion and deletion are known as rotations. In the context of red-black trees, these operations are easily understood as the transformations needed to transform a 3-node whose red link leans to the left to a 3-node whose red link leans to the right and vice- versa. The Java code for these op- erations (for a Node type that we will consider late that contains a left link, a right link, and a color  eld that can be set to the value RED to represent the color of the incoming link) is given to the left and to the right on this page. Rotations obvi- ously preserve the two invariants stated above.
 
In red-black trees, we also use a simple operation known as a color  ip (shown at the bottom of this
 
page). In terms of 2-3-4 trees, a color  ip is the essential operation: it corresponds to splitting a 4-node and passing the middle node up to the parent. A color  ip obviously does not change the number of black links on any path from the root to the bottom, but it may introduce two consecu- tive red links higher in the tree, which must be corrected.
 
Red-black BST algorithms differ on whether and when they do rotations and color  ips, in order to maintain the global invariants stated at the top of this page.
 
<code>
 
  '''Node''' rotateRight(h : '''Node'''):
 
  x = h.left
 
  h.left= x.right
 
  x.right= h
 
  x.color = h.color
 
  h.color = RED
 
    '''return''' x
 
</code>
 
  
<code>
+
Основные операции, используемые алгоритмами сбалансированного дерева для поддержания баланса при вставке и удалении, называются вращением вправо и вращением влево. Первая операция трансформируют <tex>3</tex>-узел (совокупность из <tex>3</tex> узлов, где <tex>2</tex> узла являются наследниками третьего, причем одна из связей является красной), левый потомок которого окрашен в красный, в  <tex>3</tex>-узел, правый потомок которого окрашен в красный,вторая операция {{---}} наоборот.  Вращения сохраняют два указанных выше инварианта, не изменяют поддеревья узла.
   '''Node''' rotateLeft(h : '''Node'''):
+
===Псевдокод===
   x = h.right
+
[[File:rotateRight.png|310px|thumb|upright|Rotate Right]]
  h.right = x.left
+
   '''Node''' rotateRight(h : '''Node''')  
  x.left = h
+
      x = h.left
  x.color = h.color
+
      h.left = x.right
  h.color = RED
+
      x.right = h
  '''return''' x
+
      x.color = h.color
</code>
+
      h.color = RED
 +
      '''return''' x
 +
[[File:rotateLeft.png|310px|thumb|upright|Rotate Left]]
 +
   '''Node''' rotateLeft(h : '''Node''')
 +
      x = h.right
 +
      h.right = x.left
 +
      x.left = h
 +
      x.color = h.color
 +
      h.color = RED
 +
      '''return''' x
  
<code>
+
==Переворот цветов==
   '''void''' flipColors(h : '''Node''' h):
+
В красно-черных деревьях используется такая  операция как '''переворот цветов''' , которая инвертирует цвет узла и двух его детей.  Она не изменяет количество черных узлов  на любом пути от корня до листа, но может привести к появлению двух последовательных красных узлов.
  h.color = '''!'''h.color
+
===Псевдокод===
  h.left.color = '''!'''h.left.color
+
[[File: ColorFlip.png|320px|thumb|upright| Переворот цветов]]
  h.right.color = '''!'''h.right.color
+
   '''void''' flipColors(h : '''Node''' h)  
</code>
+
      h.color = '''!''' h.color
 +
      h.left.color = '''!''' h.left.color
 +
      h.right.color = '''!''' h.right.color
  
==Методы==
+
==Вставка==
 +
Вставка в ЛСКЧД базируется на <tex>4</tex> простых операциях:
 +
 
 +
*Вставка нового узла к листу дерева:
 +
Если высота узла  нулевая, возвращаем новый красный узел.
 +
[[File:insertNode.png|310px|thumb|upright|Вставка нового узла]]
 +
*Расщепление узла с <tex>4</tex>-я потомками:
 +
Если левый предок и правый предок  красные, запускаем переворот цветов от текущего узла.
 +
[[File:Split4node.png|310px|thumb|upright|Расщепление узла]]
 +
*Принудительное вращение влево:
 +
[[File:Enforce.png|310px|thumb|upright|Принудительное вращение]]
 +
Если правый предок красный, вращаем текущую вершину влево.
 +
*Балансировка узла с <tex>4</tex>-я потомками:
 +
[[File:Balance4node.png|310px|thumb|Балансировка]]
 +
Если левый предок красный и левый предок левого предка красный, то вращаем текущую вершину вправо.
 +
 
 +
 
 +
===Псевдокод===
 +
  '''void''' insert(key : '''Key''', value : '''Value''' )
 +
        root = insert(root, key, value)
 +
        root.color = BLACK
  
<code>
 
  '''void''' insert( '''key''' : Key, '''value''' : Value ):
 
    root = insert(root, key, value)
 
    root.color = BLACK
 
</code>
 
  
<code>
+
  '''Node''' insert(h : '''Node''', key : '''Key''', value : '''Value''')
      '''Node''' insert( h : '''Node''', key : '''Key''', value : '''Value'''):
+
      <span style="color:#008000">// Вставка нового листа</span>
        '''if''' h == ''null''     
+
      '''if''' h == ''null''     
 
           '''return''' '''new''' Node(key, value)
 
           '''return''' '''new''' Node(key, value)
          '''if''' isRed(h.left) '''&&''' isRed(h.right)
+
      <span style="color:#008000">// Расщепление узла с <tex>4</tex>-я потомками</span>
            colorFlip(h)
+
      '''if''' isRed(h.left) '''&&''' isRed(h.right)
          '''int''' cmp = key.compareTo(h.key)
+
          colorFlip(h)
           '''if'''  cmp == 0
+
      <span style="color:#008000">// Стандартная вставка [[Дерево поиска, наивная реализация|в дереве поиска]]</span>
            h.val = value
+
      '''if''' key = h.key  
 +
          h.val = value
 +
      '''else'''
 +
           '''if''' key < h.key  
 +
              h.left = insert(h.left, key, value
 
           '''else'''  
 
           '''else'''  
            '''if''' cmp < 0
 
              h.left = insert(h.left, key, value) 
 
            '''else'''
 
 
               h.right = insert(h.right, key, value)
 
               h.right = insert(h.right, key, value)
           '''if''' isRed(h.right) '''&&''' '''!'''isRed(h.left)  
+
          <span style="color:#008000">// Принудительное вращение влево</span>
            h = rotateLeft(h)
+
           '''if''' isRed(h.right) '''&&''' '''!'''isRed(h.left)
 +
              h = rotateLeft(h)
 +
          <span style="color:#008000">// Балансировка узла с <tex>4</tex>-я потомками</span>
 
           '''if''' isRed(h.left) '''&&''' isRed(h.left.left)
 
           '''if''' isRed(h.left) '''&&''' isRed(h.left.left)
            h = rotateRight(h)
+
              h = rotateRight(h)
    '''return''' ''h''
+
      '''return''' h
</code>
 
  
<code>
+
==Поиск==
  '''Value''' search(key : '''Key'''):
+
Поиск в левосторонних красно-черных деревьях эквивалентен поиску в [[Дерево поиска, наивная реализация|наивной реализации дерева поиска]].
  '''Node''' x = root
+
Для поиска элемента в красно-черных деревьях дереве поиска можно воспользоваться циклом,который проходит от корня до искомого элемента. Если же элемент отсутствует, цикл пройдет до листа дерева и прервется. Для каждого узла цикл сравнивает значение его ключа с искомым ключом. Если ключи одинаковы, то функция возвращает текущий узел, в противном случае цикл повторяет для левого или правого поддерева. Узлы, которые посещает функция образуют нисходящий путь от корня, так что время ее работы <tex>O(h)</tex>, где <tex>h</tex> {{---}} высота дерева.
  '''while''' x '''!'''= null
+
===Псевдокод===
    '''int''' cmp = key.compareTo(x.key)
+
'''Value''' search(key : '''Key''')
    '''if''' cmp == 0
+
    '''Node''' x = root
      '''return''' x.val
+
    '''while''' (x '''!'''= null)
    '''else'''
+
      '''if''' key = x.key
      '''if''' cmp < 0
+
          '''return''' x.val
        x = x.left
+
      '''else'''
 +
          '''if''' key < x.key
 +
              x = x.left
 
       '''else'''  
 
       '''else'''  
        '''if''' cmp > 0
+
          '''if''' key > x.key
          x = x.right
+
              x = x.right
  '''return''' ''null''
+
    '''return''' ''null''
</code>
 
  
==Удаление==
+
==Исправление правых красных связей==
<code>
+
*Использование Переворота цветов и вращений  сохраняет баланс черной связи.
  '''void''' deleteMin():
+
*После удаления необходимо исправить правые красные связи и устранить узлы с <tex>4</tex>-я потомками
  root = deleteMin(root)
+
      <span style="color:#008000">// Исправление правых красных связей</span>
  root.color = BLACK
+
  '''Node''' fixUp(h : '''Node''')  
</code>
+
      '''if''' isRed(h.right)
 +
          h = rotateLeft(h)
 +
      <span style="color:#008000">// Вращение <tex>2</tex>-ой красной пары пары</span>
 +
      '''if''' isRed(h.left) '''&&''' isRed(h.left.left)
 +
          h = rotateRight(h) 
 +
      <span style="color:#008000">// Балансировка узла с <tex>4</tex>-я потомками</span>
 +
      '''if''' isRed(h.left) '''&&''' isRed(h.right)
 +
          colorFlip(h) 
 +
      '''return''' h
  
<code>
+
==Удаление максимума==
'''Node''' deleteMin( h : '''Node'''):
+
* Спускаемся вниз по правому краю  дерева.
  '''if''' h.left == ''null''
+
* Если поиск заканчивается на узле с <tex>4</tex>-мя или <tex>5</tex>-ю потомками, просто удаляем узел.
      '''return''' ''null''
 
  '''if''' !isRed(h.left) '''&&''' !isRed(h.left.left)
 
      h = moveRedLeft(h)
 
  h.left = deleteMin(h.left)
 
  '''return''' fixUp(h)
 
</code>
 
  
<code>
+
[[File:34-nodeRemove.png|310px|thumb|center| Узлы до и после удаления]]
  '''Node''' moveRedLeft('''Node''' h):
+
* Удаление узла с <tex>2</tex>-я потомками нарушает баланс
    colorFlip(h):
+
Соответственно, спускаясь вниз по дереву необходимо поддерживать следующий инвариант : количество потомков узла не должно быть ровно <tex>2</tex>-м.
    '''if''' isRed(h.right.left)
+
[[File:changeNode.png|600px|thumb|center| ]]
      h.right = rotateRight(h.right)
+
      h = rotateLeft(h)
+
Будем поддерживать инвариант: для любого узла либо сам узел, либо правый предок узла '''красный'''.
      colorFlip(h)
+
Будем придерживаться тактики , что удалять лист легче, чем внутренний узел.
'''return''' h 
 
</code> 
 
  
<code>
+
Заметим, что если правый потомок вершины и правый потомок правого потомка вершины черные, необходимо переместить левую красную ссылку вправо для сохранения инварианта.
  '''Node''' moveRedRight(h :'''Node''' ):
+
[[File:MinEasy.png|400px|thumb|right| Перемещение красной ссылки. Простой случай]]
    colorFlip(h)
 
    '''if''' isRed(h.left.left))
 
      h = rotateRight(h)
 
      colorFlip(h)
 
'''return''' h 
 
</code>
 
<code>
 
'''void''' delete(key : '''Key'''):
 
  root = delete(root, key)
 
  root.color = BLACK
 
</code>
 
  
<code>
+
[[File:MinHard.png|400px|thumb|right| Перемещение красной ссылки. Сложный случай]]
  '''Node''' delete('''Node''' : h, '''Key''' : key):
+
 
    '''if''' key.compareTo(h.key) < 0)   
+
===Псевдокод===
          '''if''' !isRed(h.left) '''&&''' !isRed(h.left.left)
+
'''void''' deleteMax()             
            h = moveRedLeft(h)
+
    root = deleteMax(root)       
          h.left =  delete(h.left, key)
+
    root.color = BLACK             
    '''else'''   
+
 
      '''if''' isRed(h.left)
+
'''Node''' moveRedLeft(h : '''Node''')
        h = rotateRight(h)
+
    colorFlip(h)                    
      '''if''' key.compareTo(h.key) == 0 '''&&''' (h.right == null)
+
    '''if''' isRed(h.right.left              
        '''return''' ''null''
+
        h.right = rotateRight(h.right)      
      '''if''' !isRed(h.right) '''&&''' !isRed(h.right.left)
+
        h = rotateLeft(h)                  
        h = moveRedRight(h)
+
        colorFlip(h)                        
      '''if''' key.compareTo(h.key) == 0
+
    '''return''' h                                         
        h.val = get(h.right, min(h.right).key)
+
 
        h.key = min(h.right).key
+
  '''Node''' deleteMax(h : '''Node''')
        h.right = deleteMin(h.right)
+
    '''if''' isRed(h.left)                                        
       '''else'''  
+
    <span style="color:#008000">// вращаем все 3-вершины вправо</span>
        h.right = delete(h.right, key)
+
        h = rotateRight(h)
  '''return''' fixUp(h)
+
    <span style="color:#008000">// поддерживаем инвариант (h должен быть красным)</span>
</code>
+
    '''if''' h.right == ''null''
 +
        return ''null''
 +
    <span style="color:#008000">// заимствуем у брата если необходимо</span>
 +
    '''if''' !isRed(h.right) '''&&''' !isRed(h.right.left)  
 +
        h = moveRedRight(h)
 +
    <span style="color:#008000">// опускаемся на один уровень глубже </span>
 +
    h.left = deleteMax(h.left)
 +
    <span style="color:#008000">// исправление правых красных ссылок и 4-вершин на пути вверх</span>
 +
    '''return''' fixUp(h)
 +
 
 +
==Удаление минимума==
 +
Поддерживаем инвариант: вершина или левый ребенок вершины красный.
 +
 
 +
Заметим, что если  левый потомок вершины и левый потомок левого потомка вершины черные, необходимо переместить красную ссылку для сохранения инварианта.
 +
[[File:MoveRedLeftEasy.png.png |400px|thumb|upright|Перемещение красной ссылки. Простой случай]]
 +
[[File:MoveRedLeftNoEasy.png|400px|thumb|upright|Перемещение красной ссылки. Сложный случай]]
 +
===Псевдокод===
 +
'''Node''' moveRedLeft(h : '''Node''')
 +
    colorFlip(h)
 +
    if isRed(h.right.left)
 +
        h.right = rotateRight(h.right)
 +
        h = rotateLeft(h)
 +
        colorFlip(h)
 +
    '''return''' h
 +
 
 +
'''void''' deleteMin()
 +
    root = deleteMin(root)
 +
    root.color = BLACK
 +
 
 +
'''Node''' deleteMin(h : '''Node''')
 +
    <span style="color:#008000">// удаляем узел на нижнем уровне(h должен быть красным по инварианту)</span>
 +
    if h.left == ''null'' 
 +
        '''return''' ''null''
 +
       <span style="color:#008000">// Если необходимо, пропушим  красную ссылку вниз</span>
 +
    '''if  (!'''isRed(h.left) '''&&  !'''isRed(h.left.left))
 +
          h = moveRedLeft(h)
 +
      <span style="color:#008000">// опускаемся на уровень ниже </span>
 +
    h.left = deleteMin(h.left)
 +
    '''return''' fixUp(h)
 +
 
 +
==Асимптотика==
 +
Асимптотика методов в левосторонних красно-черных деревьях эквивалентна асимптотике [[Красно-черное дерево|базовой реализации красно-черных деревьях]].
 +
 
 +
== См.также ==
 +
*[[Красно-черное дерево]]
 +
*[[Дерево поиска, наивная реализация]]
 +
==Источники информации==
 +
* Robert Sedgewick "Left-leaning Red-Black Trees" ,Department of Computer Science, Princeton University
 +
[[Категория: Алгоритмы и структуры данных]]

Текущая версия на 19:08, 4 сентября 2022

Определение:
Левостороннее красно-черное дерево — тип сбалансированного двоичного дерева поиска, гарантирующий такую же асимптотическую сложность операций, как у красно-черного дерева поиска.


Свойства

  • Корневой узел всегда черный.
  • Каждый новый узел всегда окрашен в красный цвет.
  • Каждый дочерний нулевой узел листа дерева считается черным.

Вращения

Чтобы поддерживать левосторонние красно-черные двоичные деревья поиска необходимо соблюдать следующие инварианты при вставке и удалении:

  • Ни один путь от корня до листьев дерева не содержит двух последовательных красных узлов.
  • Количество черных узлов на каждом таком пути одинаково.

Основные операции, используемые алгоритмами сбалансированного дерева для поддержания баланса при вставке и удалении, называются вращением вправо и вращением влево. Первая операция трансформируют [math]3[/math]-узел (совокупность из [math]3[/math] узлов, где [math]2[/math] узла являются наследниками третьего, причем одна из связей является красной), левый потомок которого окрашен в красный, в [math]3[/math]-узел, правый потомок которого окрашен в красный,вторая операция — наоборот. Вращения сохраняют два указанных выше инварианта, не изменяют поддеревья узла.

Псевдокод

Rotate Right
  Node rotateRight(h : Node) 
      x = h.left
      h.left = x.right
      x.right = h
      x.color = h.color
      h.color = RED
      return x
Rotate Left
  Node rotateLeft(h : Node) 
      x = h.right
      h.right = x.left
      x.left = h
      x.color = h.color
      h.color = RED
      return x

Переворот цветов

В красно-черных деревьях используется такая операция как переворот цветов , которая инвертирует цвет узла и двух его детей. Она не изменяет количество черных узлов на любом пути от корня до листа, но может привести к появлению двух последовательных красных узлов.

Псевдокод

Переворот цветов
 void flipColors(h : Node h) 
      h.color = ! h.color
      h.left.color = ! h.left.color
      h.right.color = ! h.right.color

Вставка

Вставка в ЛСКЧД базируется на [math]4[/math] простых операциях:

  • Вставка нового узла к листу дерева:

Если высота узла нулевая, возвращаем новый красный узел.

Вставка нового узла
  • Расщепление узла с [math]4[/math]-я потомками:

Если левый предок и правый предок красные, запускаем переворот цветов от текущего узла.

Расщепление узла
  • Принудительное вращение влево:
Принудительное вращение

Если правый предок красный, вращаем текущую вершину влево.

  • Балансировка узла с [math]4[/math]-я потомками:
Балансировка

Если левый предок красный и левый предок левого предка красный, то вращаем текущую вершину вправо.


Псевдокод

 void insert(key : Key, value : Value ) 
        root = insert(root, key, value)
        root.color = BLACK


 Node insert(h : Node, key : Key, value : Value)
      // Вставка нового листа
     if h == null     
         return new Node(key, value)
      // Расщепление узла с [math]4[/math]-я потомками
     if isRed(h.left) && isRed(h.right)
         colorFlip(h)
      // Стандартная вставка в дереве поиска
     if key = h.key 
         h.val = value
     else 
         if key < h.key  
             h.left = insert(h.left, key, value)  
         else 
             h.right = insert(h.right, key, value)
          // Принудительное вращение влево
         if isRed(h.right) && !isRed(h.left)
             h = rotateLeft(h)
          // Балансировка узла с [math]4[/math]-я потомками
         if isRed(h.left) && isRed(h.left.left)
             h = rotateRight(h)
     return h

Поиск

Поиск в левосторонних красно-черных деревьях эквивалентен поиску в наивной реализации дерева поиска. Для поиска элемента в красно-черных деревьях дереве поиска можно воспользоваться циклом,который проходит от корня до искомого элемента. Если же элемент отсутствует, цикл пройдет до листа дерева и прервется. Для каждого узла цикл сравнивает значение его ключа с искомым ключом. Если ключи одинаковы, то функция возвращает текущий узел, в противном случае цикл повторяет для левого или правого поддерева. Узлы, которые посещает функция образуют нисходящий путь от корня, так что время ее работы [math]O(h)[/math], где [math]h[/math] — высота дерева.

Псевдокод

Value search(key : Key)
    Node x = root
    while (x != null)
      if key = x.key
          return x.val
      else
          if key < x.key
              x = x.left
      else 
          if key > x.key 
              x = x.right
    return null

Исправление правых красных связей

  • Использование Переворота цветов и вращений сохраняет баланс черной связи.
  • После удаления необходимо исправить правые красные связи и устранить узлы с [math]4[/math]-я потомками
      // Исправление правых красных связей
  Node fixUp(h : Node)  
      if isRed(h.right)  
          h = rotateLeft(h)  
      // Вращение [math]2[/math]-ой красной пары пары
      if isRed(h.left) && isRed(h.left.left)
          h = rotateRight(h)  
      // Балансировка узла с [math]4[/math]-я потомками
      if isRed(h.left) && isRed(h.right)
          colorFlip(h)  
      return h

Удаление максимума

  • Спускаемся вниз по правому краю дерева.
  • Если поиск заканчивается на узле с [math]4[/math]-мя или [math]5[/math]-ю потомками, просто удаляем узел.
Узлы до и после удаления
  • Удаление узла с [math]2[/math]-я потомками нарушает баланс

Соответственно, спускаясь вниз по дереву необходимо поддерживать следующий инвариант : количество потомков узла не должно быть ровно [math]2[/math]-м.

ChangeNode.png

Будем поддерживать инвариант: для любого узла либо сам узел, либо правый предок узла красный. Будем придерживаться тактики , что удалять лист легче, чем внутренний узел.

Заметим, что если правый потомок вершины и правый потомок правого потомка вершины черные, необходимо переместить левую красную ссылку вправо для сохранения инварианта.

Перемещение красной ссылки. Простой случай
Перемещение красной ссылки. Сложный случай

Псевдокод

void deleteMax()              
    root = deleteMax(root)         
    root.color = BLACK               
Node moveRedLeft(h : Node)
    colorFlip(h)                     
    if isRed(h.right.left                
        h.right = rotateRight(h.right)       
        h = rotateLeft(h)                   
        colorFlip(h)                          
    return h                                           
Node deleteMax(h : Node)
    if isRed(h.left)                                         
    // вращаем все 3-вершины вправо
        h = rotateRight(h)
    // поддерживаем инвариант (h должен быть красным)
    if h.right == null
        return null
    // заимствуем у брата если необходимо
    if !isRed(h.right) && !isRed(h.right.left) 
        h = moveRedRight(h)
    // опускаемся на один уровень глубже 
    h.left = deleteMax(h.left) 
    // исправление правых красных ссылок и 4-вершин на пути вверх
    return fixUp(h)

Удаление минимума

Поддерживаем инвариант: вершина или левый ребенок вершины красный.

Заметим, что если левый потомок вершины и левый потомок левого потомка вершины черные, необходимо переместить красную ссылку для сохранения инварианта.

Перемещение красной ссылки. Простой случай
Перемещение красной ссылки. Сложный случай

Псевдокод

Node moveRedLeft(h : Node)
    colorFlip(h)
    if isRed(h.right.left)
        h.right = rotateRight(h.right)
        h = rotateLeft(h)
        colorFlip(h)
    return h
void deleteMin()
    root = deleteMin(root)
    root.color = BLACK
Node deleteMin(h : Node)
    // удаляем узел на нижнем уровне(h должен быть красным по инварианту)
    if h.left == null   
        return null
     // Если необходимо, пропушим  красную ссылку вниз
    if  (!isRed(h.left) &&  !isRed(h.left.left))
         h = moveRedLeft(h)
     // опускаемся на уровень ниже 
    h.left = deleteMin(h.left)
    return fixUp(h)

Асимптотика

Асимптотика методов в левосторонних красно-черных деревьях эквивалентна асимптотике базовой реализации красно-черных деревьях.

См.также

Источники информации

  • Robert Sedgewick "Left-leaning Red-Black Trees" ,Department of Computer Science, Princeton University