Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
инф-госы теория и практика.doc
Скачиваний:
28
Добавлен:
29.08.2019
Размер:
3.77 Mб
Скачать

7. Динамические структуры данных: двоичные деревья

Граф называется связным, если между двумя вершинами в нем существует маршрут (вершины называются взаимодостижимыми). Деревом называется связный граф, не содержащий циклов.

Дерево — это совокупность элементов, называемых узлами (при этом один из них определен как корень), и отношений (родительский–дочерний), образующих иерархическую структуру узлов. Узлы могут являться величинами любого простого или структурированного типа, за исключением файлового. Узлы, которые не имеют ни одного последующего узла, называются листьями. В двоичном (бинарном) дереве каждый узел может быть связан не более чем двумя другими узлами. Рекурсивно двоичное дерево определяется так: двоичное дерево бывает либо пустым (не содержит ни одного узла), либо содержит узел, называемый корнем, а также два независимых поддерева - левое поддерево и правое поддерево.

Д воичное дерево поиска может быть либо пустым, либо оно обладает таким свойством, что корневой элемент имеет большее значение узла, чем любой элемент в левом поддереве, и меньшее или равное, чем элементы в правом поддереве. Указанное свойство называется характеристическим свойством двоичного дерева поиска и выполняется для любого узла такого дерева, включая корень. Такое название двоичные деревья поиска получили по той причине, что скорость поиска в них примерно такая же, что и в отсортированных массивах: O(n) = C • log2n (в худшем случае O(n) = n).

Пример. Для набора данных 9, 44, 0, –7, 10, 6, –12, 45 построить двоичное дерево поиска.

Согласно определению двоичного дерева поиска число 9 помещаем в корень, все значения, меньшие его — на левое поддерево, большие или равные — на правое. В каждом поддереве очередной элемент можно рассматривать как корень и действовать по тому же алгоритму. В итоге получаем

Выделим типовые операции над двоичными деревьями поиска:

добавление элемента в дерево;

удаление элемента из дерева;

обход дерева (для печати элементов и т.д.);

поиск в дереве.

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

Пусть двоичное дерево поиска описывается следующим типом

Type

BT=LongInt;

U = ^BinTree;

BinTree = Record;

Inf : BT;

L, R : U;

End;

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

Существует несколько способов обхода (прохождения) всех узлов дерева. Три наиболее часто используемых из них называются обход в прямом (префиксном) порядке, обход в обратном (постфиксном) порядке и обход во внутреннем порядке (или симметричный обход). Каждый из обходов реализуется с использованием рекурсии.

По сравнению с предыдущими задача удаления узла из дерева реализуется несколько сложнее. Можно выделить два случая удаления элемента x (случай отсутствия элемента в дереве является вырожденным):

1) узел, содержащий элемент x, имеет степень не более 1 (степень узла — число поддеревьев, выходящих из этого узла);

2) узел, содержащий элемент x, имеет степень 2.

Случай 1 не представляет сложности. Предыдущий узел соединяется либо с единственным поддеревом удаляемого узла (если степень удаляемого узла равна 1), либо не будет иметь поддерева совсем (если степень узла равна 0).

Намного сложнее, если удаляемый узел имеет два поддерева. В этом случае нужно заменить удаляемый элемент самым правым элементом из его левого поддерева.

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

Идеально сбалансированное дерево – дерево в котором высоты правого и левого поддеревьев равны.

АВЛ-деревья (сбалансированные деревья) – в каждом элементе которого высоты поддеревьев отличаются не более чем на 1.

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

Для любого АВЛ-дерева высоты k с п узлами выполняет­ся соотношение k + 1 < logα п = logα 2 log2 n ≈ 1,44 • log2 n, что обеспечивает «логарифмическую трудоемкость» выполнения основных операций с АВЛ-деревом.

Идея балансировки двоичных деревьев поиска принадлежит Г. М. Адельсону-Вельскому и Е. М. Ландису, предложившим в 1962 г. класс сбалансированных деревьев, называемых с тех пор АВЛ-деревьями. Ба­ланс поддерживается с помощью процедуры вращения. Для его восста­новления в дереве с п узлами после добавления или удаления узла может потребоваться Ө(logn) вращений.

Замечательная сторона АВЛ-деревьев в том, что мы их можем поддерживать всегда в сбалансированном виде:

Пусть дан массив 5 3 2 6 1 8 7, отсортируем его и поделим на две части 1 2 3 5 6 7 8

Построим дерево

П ример: добавим элемент 13

hL = hR – баланс не нарушен

hL = hR +1 – баланс нарушится если добавим влево

hR = hL +1 – баланс нарушится если добавим вправо

|hL - hR| ≥ 2 – баланс нарушен

Корень сдвигаем по левому поддереву:

Добавим элемент 15:

=> => =>

Еще один класс деревьев поиска, называемых 2-3-деревьями, был предложен Дж. Хопкрофтом в 1970 г. Здесь баланс поддерживается за счет изменения степеней узлов. Обобщение 2-3-деревьев предложили Д. Байер и Е. Мак-Крейт. Их деревья называются Б-деревьями.

Красно-черные деревья предложил Д. Байер, назвав их симметрич­ными двоичными Б-деревьями. Л. Гибас подробно изучил их свойства и предложил использовать для наглядности красный и черный цвета.

Из многих других вариаций на тему сбалансированных дере­вьев наиболее интересны расширяющиеся деревья, которые придумали Д. Слеатор и Р. Тарьян. Эти деревья являются саморегулирующимися. Хо­рошее описание расширяющихся деревьев дал Тарьян. Расширяющиеся деревья поддерживают баланс без использования дополнительных полей (типа цвета). Вместо этого расширяющие операции, включающие враще­ния, выполняются при каждом обращении к дереву Учетная стоимость в расчете на одну операцию с деревом для расширяющихся деревьев со­ставляет О (log n).