Jump to content

Левое дерево

В информатике или левое дерево левая куча — это приоритетная очередь , реализованная с помощью варианта двоичной кучи . Каждый узел x имеет s-значение , которое представляет собой расстояние до ближайшего листа поддерева с корнем в x. [1] В отличие от двоичной кучи , левое дерево пытается быть очень несбалансированным. В дополнение к свойству кучи сохраняются левые деревья, поэтому правый потомок каждого узла имеет меньшее значение s.

Левое дерево со смещением по высоте было изобретено Кларком Алланом Крэйном . [2] Название происходит от того факта, что левое поддерево обычно выше правого.

Левое дерево — это объединяемая куча . При вставке нового узла в дерево создается новое одноузловое дерево, которое объединяется с существующим деревом. Чтобы удалить элемент, он заменяется слиянием его левого и правого поддеревьев. Обе эти операции занимают время O(log n ). Для вставок это медленнее, чем кучи Фибоначчи , которые поддерживают вставку за O(1) (постоянное) амортизированное время и O(log n ) в худшем случае.

Левые деревья имеют преимущество из-за их способности быстро сливаться по сравнению с двоичными кучами, которые принимают Θ( n ). Почти во всех случаях объединение косых куч обеспечивает более высокую производительность. Однако слияние левых куч имеет наихудшую сложность O(log n ), тогда как слияние косых куч имеет только амортизированную сложность O(log n ).

Предвзятость [ править ]

Обычное левое дерево — это левое дерево со смещением по высоте . [2] Однако могут существовать и другие отклонения, например, в левом дереве со смещением по весу . [3]

S-значение [ править ]

S-значения левого дерева

( S-значение или ранг ) узла — это расстояние от этого узла до ближайшей пустой позиции в поддереве с корнем в этом узле. Другими словами, s-значение a null ребенок неявно равен нулю. Другие узлы имеют s-значение, равное еще одному минимальному из s-значений их дочерних узлов. Таким образом, в примере справа все узлы, по крайней мере, с одним отсутствующим дочерним элементом, имеют s-значение, равное 1, а узел 4 имеет s-значение, равное 2, поскольку его правый дочерний элемент (8) имеет s-значение, равное 1. (В некоторых описаниях значение s нулевых дочерних элементов предполагается равным -1. [4] )

Зная, что кратчайший путь к ближайшему отсутствующему листу в поддереве с корнем в x равен ровно s ( x ), каждый узел на глубине s ( x )−1 или меньше имеет ровно 2 потомка, поскольку s ( x ) было бы меньше, если бы не . Это означает, что размер дерева с корнем в x не менее . Таким образом, s ( x ) не более чем , m — количество узлов поддерева с корнем в x . [1]

Операции над левым деревом со смещением по высоте [ править ]

Большинство операций над левым деревом со смещением по высоте выполняются с использованием операции слияния. [1]

Объединение двух минимальных HBLT [ править ]

Операция слияния принимает в качестве входных данных два Min HBLT и возвращает Min HBLT, содержащий все узлы исходного Min HBLT, вместе взятые.

Если любой из A или B пуст, слияние возвращает другой.

В случае Min HBLT предположим, что у нас есть два дерева с корнями в A и B, где A.key Б.ключ. В противном случае мы можем поменять местами A и B, чтобы выполнено приведенное выше условие.

Слияние выполняется рекурсивно путем слияния B с правым поддеревом A. Это может изменить значение S правого поддерева A. Чтобы сохранить свойство левого дерева, после каждого слияния мы проверяем, стало ли S-значение правого поддерева больше, чем S-значение левого поддерева во время рекурсивных вызовов слияния. Если да, то меняем местами правое и левое поддеревья (если один дочерний элемент отсутствует, он должен быть правым).

Поскольку мы предположили, что корень A больше, чем корень B, свойство кучи также сохраняется.

Псевдокод для слияния двух левых деревьев со смещением по минимальной высоте [ править ]

ОБЪЕДИНИТЬ(А, Б)     если  A = ноль,  верните  B     если  B = ноль,  верните  A     если  A.key > B.key,  верните  MERGE(B, A)    A.right := MERGE (A.right, B)  // результат не может быть нулевым, поскольку B не равен нулю,      если  A.left = null  , то         СМЕНА(А.слева, А.справа)        A.s_value := 1  // поскольку правое поддерево равно нулю, кратчайший путь к листу-потомку от узла A равен 1          return  A     если  A.right.s_value > A.left.s_value  , то         SWAP (А.правый, А.левый)    A.s_value := A.right.s_value + 1     вернуть  А 

Java-код для слияния двух левых деревьев со сдвигом по минимальной высоте [ править ]

публичное   узлов   слияние  (  узел   x  ,   узел   y  )   {      if   (  x   ==   null  )          return   y  ;      если   (  y   ==   null  )           вернуть   x  ;      // если бы это была максимальная куча, то      // следующей строкой было бы: if (x.element < y.element)      if   (  x  .  element  .  CompareTo  (  y  .  element  )   >   0  )          // x.element > y.element          возвращает   слияние   (  y  ,   x  );      х  .  rightChild   =   слияние  (  x  .  rightChild  ,   y  );      if   (  x  .  leftChild   ==   null  )   {          // левый дочерний элемент не существует, поэтому переместите правый дочерний элемент в левую сторону          x  .  левыйребенок   =   х  .  правый ребенок  ;          х  .  rightChild   =   ноль  ;          // xs был и остается 1      }   else   {          // левый дочерний элемент существует, поэтому сравниваем s-значения          if   (  x  .  leftChild  .  s   <   x  .  rightChild  .  s  )   {              Node   temp   =   x  .  левый ребенок  ;              х  .  левыйребенок   =   х  .  правый ребенок  ;              х  .  правый ребенок   =   темп  ;          }          // поскольку мы знаем, что правый дочерний элемент имеет меньшее значение s, мы можем          // просто добавить единицу к его s-значению          x  .  с   =   х  .  правильно, Ребенок  .  с   +   1  ;      }      Вернуть   х  ;  } 

Код на Haskell для слияния двух левых деревьев со смещением по минимальной высоте [ править ]

данные   LHeap   a    =   Лист    |   Узел   a   (  LHeap   a  )   (  LHeap   a  )  ранг   ::   LHeap   a   ->   Целочисленный  ранг   Лист   =   0  ранг   (  Node   _   _   r  )   =   ранг   r   +   1  слияние   ::   Ord   a   =>   LHeap   a   ->   LHeap   a   ->   LHeap   a  слияние   Лист   h   =   h  слияние   h   Лист   =   h  слияние   h  @  (  Узел   a   l   r  )   h'  @  (  Узел   a'   _   _  )    |   а   >   а'             =   объединить   ч'   ч    |   ранг   r'   >   ранг   l   =   узел   a   r'   l    |   в противном случае          =   Node   a   l   r'    , где   r'   =   слияние   r   h' 

Пример [ править ]

Показан пример того, как работает операция слияния в левом дереве. Поля представляют каждый вызов слияния.

Когда рекурсия завершается, мы меняем местами левых и правых дочерних элементов, если x.right.s_value > x.left.s_value для каждого узла x. В данном случае мы поменяли местами поддеревья с корнями в узлах с ключами 7 и 10.

Внесение в минимальный HBLT [ править ]

Вставка осуществляется с помощью операции слияния. Вставка узла в уже существующий

Min HBLT: создает дерево HBLT размером один с этим узлом и объединяет его с существующим деревом.

ВСТАВИТЬ (  А  ,  х  )     B  := CREATE_TREE(  x  )     вернуть  СЛИЯНИЕ(  A  ,  B  ) 

Удаление элемента Min из Min HBLT [ править ]

Элемент Min в Min HBLT является корневым. Таким образом, чтобы удалить Min, корень удаляется, а его поддеревья объединяются для формирования нового Min HBLT.

DELETE_MIN(  А  )     x  :=  A  .key     A  := ОБЪЕДИНИТЬ (  A  .right,  A  .left)     вернуть   х 

Инициализация левого дерева со смещением по высоте [ править ]

Инициализация минимального HBLT. Часть 1.

Инициализация левого дерева со смещением по высоте в основном выполняется одним из двух способов. Первый — объединить каждый узел по одному в один HBLT. Этот процесс неэффективен и занимает время O( nlogn ). Другой подход — использовать очередь для хранения каждого узла и результирующего дерева. Первые два элемента в очереди удаляются, объединяются и помещаются обратно в очередь. Это может инициализировать HBLT за время O( n ). Этот подход подробно описан на трех прилагаемых диаграммах. Показано левое дерево со смещением минимальной высоты.

Чтобы инициализировать минимальный HBLT, поместите каждый элемент, который нужно добавить в дерево, в очередь. В примере (см. часть 1 слева) инициализируется набор чисел [4, 8, 10, 9, 1, 3, 5, 6, 11]. Каждая строка диаграммы представляет собой очередной цикл алгоритма, изображающий содержимое очереди. Первые пять шагов легко выполнить. Обратите внимание, что только что созданный HBLT добавляется в конец очереди. На пятом этапе происходит первое появление значения s больше 1. Шестой шаг показывает объединение двух деревьев друг с другом с предсказуемыми результатами.

Инициализация минимального HBLT. Часть 2.

Во второй части происходит немного более сложное слияние. Дерево с меньшим значением (дерево x) имеет правого дочернего элемента, поэтому слияние необходимо снова вызвать для поддерева, корнем которого является правый дочерний элемент дерева x и другое дерево. После слияния с поддеревом полученное дерево снова помещается в дерево x. Значение s правого дочернего элемента (s=2) теперь больше, чем значение s левого дочернего элемента (s=1), поэтому их необходимо поменять местами. Значение s корневого узла 4 теперь также равно 2.

Инициализация минимального HBLT. Часть 3.

Часть 3 – самая сложная. Здесь мы дважды рекурсивно вызываем слияние (каждый раз с правым дочерним поддеревом, которое не выделено серым цветом). Здесь используется тот же процесс, который описан в части 2.

Удаление произвольного элемента из минимального HBLT [ править ]

Если у нас есть указатель на узел x в Min HBLT, мы можем удалить его следующим образом: заменить узел x результатом слияния двух его поддеревьев и обновить s-значения узлов на пути от x до корня. , меняя местами правое и левое поддеревья, если необходимо, чтобы сохранить свойство левого дерева.

Обход вверх продолжается до тех пор, пока мы не достигнем корня или пока значение s не изменится. Поскольку мы удаляем элемент, S-значения на пройденном пути увеличить нельзя. Каждый узел, который уже является правым дочерним элементом своего родителя и приводит к уменьшению s-значения родителя, останется справа. Каждый узел, который является левым дочерним элементом своего родителя и вызывает уменьшение s-значения родителя, должен быть заменен своим правым братом, если s-значение становится ниже текущего s-значения правого дочернего узла.

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

Когда обход заканчивается в некотором узле y, все пройденные узлы лежат на крайнем правом пути с корнем в узле y. Пример показан ниже. Отсюда следует, что количество пройденных узлов не превышает log(m), где m — размер поддерева с корнем в y. Таким образом, для выполнения этой операции также требуется O(lg m).

Левое дерево со смещением по весу [5] [ редактировать ]

Левые деревья также могут быть смещены по весу. В этом случае вместо хранения s-значений в узле x мы сохраняем атрибут w( x ), обозначающий количество узлов в поддереве с корнем в x :

ш( х ) = ш( х.вправо ) + ш( х.влево ) + 1

WBLT гарантируют, что w(x.left) ≥ w(x.right) для всех внутренних узлов x. Операции WBLT обеспечивают этот инвариант путем замены дочерних элементов узла, когда правое поддерево перерастает левое, как и в операциях HBLT.

Объединение двух минимальных WBLT [ править ]

Операцию слияния в WBLT можно выполнить с помощью одного обхода сверху вниз, поскольку количество узлов в поддеревьях известно до рекурсивного вызова слияния. Таким образом, мы можем поменять местами левое и правое поддеревья, если общее количество узлов в правом поддереве и объединяемом дереве больше, чем количество узлов в левом поддереве. Это позволяет выполнять операции по одному пути и, таким образом, увеличивает временную сложность операций в постоянный коэффициент.

Операция слияния изображена на графике ниже.

на WBLT операции Другие

Вставки и удаления элемента min могут выполняться так же, как и для HBLT, с использованием операции слияния.

Хотя WBLT превосходят HBLT при слиянии, вставке и удалении ключа Min с постоянным коэффициентом, граница O (log n ) не гарантируется при удалении произвольного элемента из WBLT, поскольку θ( n необходимо пересечь узлы ).

Если бы это был HBLT, то удаление листового узла с ключом 60 заняло бы время O (1), а обновление s-значений не требуется, поскольку длина крайнего правого пути для всех узлов не меняется.

Но в дереве WBLT нам приходится обновлять вес каждого узла обратно до корня, что в худшем случае занимает O ( n ).

Варианты [ править ]

Существует несколько вариаций базового левого дерева, которые вносят лишь незначительные изменения в базовый алгоритм:

  • Выбор левого ребенка как более высокого произволен; «правое дерево» тоже подойдет.
  • Можно избежать замены дочерних элементов, а вместо этого записать, какой дочерний элемент самый высокий (например, в младшем бите s-значения) и использовать его в операции слияния.
  • Значение s, используемое для принятия решения о том, с какой стороной объединяться, может использовать метрику, отличную от высоты. Например, можно использовать вес (количество узлов).

Ссылки [ править ]

  1. Перейти обратно: Перейти обратно: а б с «Левые деревья» (PDF) . www.google.com . Проверено 31 мая 2019 г.
  2. Перейти обратно: Перейти обратно: а б Крейн, Кларк А. (1972), Линейные списки и очереди с приоритетами как сбалансированные двоичные деревья (докторская диссертация), Департамент компьютерных наук, Стэнфордский университет, ISBN  0-8240-4407-Х , СТАН-CS-72-259
  3. ^ Сонхун Чо; Сартадж Сахни (1996), «Левые деревья со смещением по весу и модифицированные списки пропуска» (PDF) , Журнал экспериментальной алгоритмики , 3 : 2, CiteSeerX   10.1.1.13.2962 , doi : 10.1145/297096.297111 , S2CID   17789668
  4. ^ Стюарт, Джеймс (25 сентября 1988 г.). «ЛЕВЫЕ ДЕРЕВЬЯ» . Проект динамической графики Университета Торонто . Проверено 31 мая 2019 г.
  5. ^ Чо, Сонхун; Сахни, Сартадж (сентябрь 1998 г.). «Левые деревья с учетом веса и модифицированные списки пропуска» . Дж. Эксп. Алгоритмика . 3 :2. дои : 10.1145/297096.297111 . ISSN   1084-6654 . S2CID   17789668 .

Дальнейшее чтение [ править ]

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: ee04d98f77eedc6b0d45648e90f5b98d__1705100340
URL1:https://arc.ask3.ru/arc/aa/ee/8d/ee04d98f77eedc6b0d45648e90f5b98d.html
Заголовок, (Title) документа по адресу, URL1:
Leftist tree - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)