Jump to content

Резьбовое двоичное дерево

(Перенаправлено из дерева с правой резьбой )
со Связанное дерево специальными звеньями, показанными пунктирными стрелками.

В вычислительной технике двоичное дерево с резьбой — это вариант двоичного дерева , который облегчает обход в определенном порядке.

Все двоичное дерево поиска можно легко обойти в порядке основного ключа, но, имея только указатель на узел , поиск следующего узла может быть медленным или невозможным. Например, листовые узлы по определению не имеют потомков, поэтому, имея только указатель на листовой узел, никакой другой узел не может быть достигнут. Дерево с резьбой добавляет дополнительную информацию в некоторые или все узлы, так что для любого отдельного узла можно быстро найти «следующий» узел, что позволяет обход дерева без рекурсии и дополнительное хранилище (пропорциональное глубине дерева), необходимое для рекурсии.

«Двоичное дерево создается путем создания всех правых дочерних указателей, которые обычно имеют нулевое значение, указывающих на упорядоченного преемника узла ( если он существует), а все левые дочерние указатели, которые обычно имеют нулевое значение, указывают на упорядоченного предшественника. узла». [1]

Предполагается, что порядок обхода такой же, как и порядковый обход дерева. Однако указатели можно вместо (или в дополнение) добавлять к узлам дерева, а не заменять. Определенные таким образом связанные списки также обычно называются «потоками» и могут использоваться для обеспечения обхода в любом желаемом порядке. Например, дерево, узлы которого представляют информацию о людях, может быть отсортировано по имени, но иметь дополнительные потоки, позволяющие быстро перемещаться по дате рождения, весу или любой другой известной характеристике.

Мотивация

[ редактировать ]

Деревья, включая (но не ограничиваясь) деревья двоичного поиска , могут использоваться для хранения элементов в определенном порядке, например, значения некоторого свойства, хранящегося в каждом узле, часто называемого ключом . Одной из полезных операций над таким деревом является обход : посещение всех элементов в порядке ключа.

Простой алгоритм рекурсивного обхода, который посещает каждый узел двоичного дерева поиска, заключается в следующем. Предположим, t — указатель на узел или nil . «Посещение» t может означать выполнение любого действия над узлом t или его содержимым.

Алгоритм обхода( t ):

  • Входные данные: указатель t на узел (или nil ).
  • Если t = nil , вернитесь.
  • Еще:
    • траверс (левый ребенок ( т ))
    • Посетите т
    • траверс (правый ребенок ( т ))

Одна из проблем этого алгоритма заключается в том, что из-за его рекурсии он использует пространство стека, пропорциональное высоте дерева. Если дерево достаточно сбалансировано, это составляет O (log n ) пространства для дерева, содержащего n элементов. В худшем случае, когда дерево принимает форму цепочки , высота дерева равна n, поэтому алгоритм занимает O ( n ) пространства. Вторая проблема заключается в том, что все обходы должны начинаться с корня, когда узлы имеют указатели только на своих дочерних элементов. Обычно имеется указатель на конкретный узел, но этого недостаточно для возврата к остальной части дерева, если не добавлена ​​дополнительная информация, например указатели потоков.

При таком подходе может быть невозможно определить, действительно ли указатели слева и/или справа в данном узле указывают на дочерние элементы или являются следствием многопоточности. Если различие необходимо, для его записи достаточно добавить один бит к каждому узлу.

В учебнике 1968 года Дональд Кнут спросил, существует ли нерекурсивный алгоритм упорядоченного обхода, который не использует стек и оставляет дерево неизмененным. [2] Одним из решений этой проблемы является резьба деревьев, предложенная Джозефом М. Моррисом в 1979 году. [3] [4] В последующем издании 1969 г. [5] Кнут приписал представление резьбового дерева Перлису и Торнтону (1960). [6]

Связь с родительскими указателями

[ редактировать ]

Другой способ достижения аналогичных целей — включить в каждый узел указатель на родительский узел этого узла. Учитывая, что «следующий» узел всегда может быть достигнут, «правильные» указатели по-прежнему имеют значение null, когда нет правильных дочерних узлов. Чтобы найти «следующий» узел из узла, правый указатель которого равен нулю, пройдите вверх по «родительским» указателям, пока не достигнете узла, правый указатель которого не равен нулю и не является дочерним элементом, из которого вы только что вышли. Этот узел является «следующим» узлом, а за ним идут его потомки справа.

Также возможно обнаружить родителя узла из связанного двоичного дерева без явного использования родительских указателей или стека, хотя это медленнее. Чтобы убедиться в этом, рассмотрим узел k с правым дочерним элементом r . Тогда левый указатель r должен быть либо дочерним, либо обратным к k . В случае, когда r имеет левый дочерний элемент, этот левый дочерний элемент, в свою очередь, должен иметь либо собственный левый дочерний элемент, либо поток, возвращающийся к k , и так далее для всех последовательных левых дочерних элементов. Итак, следуя по цепочке левых указателей от r , мы в конечном итоге найдём поток, указывающий обратно на k . Ситуация симметрично аналогична, когда q является левым дочерним элементом p : мы можем проследить за правыми дочерними элементами q до потока, указывающего вперед на p .

В Питоне :

def parent(node):    if node is node.tree.root:        return None    x = node    y = node    while True:        if is_thread(y):            p = y.right            if p is None or p.left is not node:                p = x                while not is_thread(p.left):                    p = p.left                p = p.left            return p        elif is_thread(x):            p = x.left            if p is None or p.right is not node:                p = y                while not is_thread(p.right):                    p = p.right                p = p.right            return p        x = x.left        y = y.right
  1. Однопоточный: каждый узел связан либо с преемником по порядку с предшествующим , либо (слева или справа).
  2. Двойная резьба: каждый узел имеет резьбу как к предшественнику, так и к преемнику (слева и справа).

Массив упорядоченного обхода

[ редактировать ]

Потоки относятся к предшественникам и преемникам узла в соответствии с упорядоченным обходом.

Порядковый обход резьбового дерева A,B,C,D,E,F,G,H,I, предшественник E является D, преемник E является F.

Давайте сделаем резьбовое двоичное дерево из обычного двоичного дерева:

Обход по порядку для вышеуказанного дерева — DBAE C. Таким образом, соответствующее двоичное дерево с резьбой будет —

[ редактировать ]

В двоичном дереве с m -путями и n узлами имеется n × m − ( n −1) пустых связей.

  1. ^ Ван Вик, Кристофер Дж. Структуры данных и программы на C , Аддисон-Уэсли, 1988, стр. 175. ISBN   978-0-201-16116-8 .
  2. ^ Кнут, DE (1968). Фундаментальные алгоритмы . Искусство компьютерного программирования. Том. 1 (1-е изд.). Ридинг/Массачусетс: Эддисон Уэсли.
  3. ^ Моррис, Джозеф Х. (1979). «Обход бинарных деревьев просто и дешево». Письма об обработке информации . 9 (5). дои : 10.1016/0020-0190(79)90068-1 .
  4. ^ Матети, Прабхакер; Мангирмалани, Рави (1988). «Пересмотр алгоритма обхода дерева Морриса». Наука компьютерного программирования . 11 : 29–43. дои : 10.1016/0167-6423(88)90063-9 .
  5. ^ Кнут, DE (1969). Фундаментальные алгоритмы . Искусство компьютерного программирования. Том. 1 (2-е изд.). Эддисон Уэсли. Hre: Раздел 2.3.1 «Обход бинарных деревьев».
  6. ^ Перлис, Алан Джей; Торнтон, К. (апрель 1960 г.). «Манипулирование символами с помощью связанных списков» . Коммуникации АКМ . 3 (4): 195–204. дои : 10.1145/367177.367202 .
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: eb3138e4650c8f3704f858118e74663a__1716674700
URL1:https://arc.ask3.ru/arc/aa/eb/3a/eb3138e4650c8f3704f858118e74663a.html
Заголовок, (Title) документа по адресу, URL1:
Threaded binary tree - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)