Программирование >>  Составные структуры данных 

1 ... 164 165 166 [ 167 ] 168 169 170 ... 225


Таблица 12.2 Эмпирические исследования реализаций таблиц символов

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

конструирование

попадания при поиске

1250

2500

5000

12500

1398

25000

2551

2917

2859

5881

50000

100000

200000

Ключ: А В С Т

Неупорядоченный массив (упражнение 12.20) Упорядоченный связный список (упражнение 12.21) Бинарный поиск (программа 12,7)

Дерево бинарного поиска, стандартное (программа 12.8) Индексированное дерево бинарного поиска (упражнение 12.67)

12.8 Вставка в корень в деревьях бинарного поиска

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

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

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



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

К счастью, сушествует простое рекурсивное решение этой проблемы, которое основывается на ротации (rotation) - фундаментальном преобразовании деревьев. По сушеству, ротация позволяет менять местами роль корня и одного из его дочерних узлов при сохранении порядка ключей в узлах BST-дерева. Ротация вправо затрагивает корень и левый дочерний узел (см. рис. 12.12). Ротация помешает корень справа, изменяя на обратное направление левой связи корня: перед ротацией она указывает от корня к левому дочернему узлу, а после ротации - от левого дочернего узла (нового корня) к старому корню (правый дочерний узел нового корня). Основная часть, которая обеспечивает работу ротации, - копирование правой связи левого дочернего узла, чтобы она стала левой связью старого корня. Эта связь указывает на все узлы с ключами между двумя узлами, участвующими в ротации. И наконец, связь со старым корнем должна быть изменена так, чтобы указывать на новый корень. Описание ротации влева аналогично приведенному выше, с учетом замены оп-редлений правый и левый (см. рис. 12.13).

Ротация - это локальное изменение, затрагивающее


РИСУНОК 12.12 РОТАЦИЯ ВПРАВО В BST-ДЕРЕВЕ

Иа этой схеме показан результат (внизу) ротации вправо в узле S в примере BST-дерева (вверху). Узел, содержащий S, перемещается в дереве вниз, становясь правым дочерним узлом своего прежнего левого дочернего узла.

Ротация выполняется путем получения связи с новым корнем Е из левой связи S, установки левой связи S путем копирования правой связи Е, установки правой связи Е указывающей на Su установки связи из А указывающей не на S, а на Е. Эффект ротации заключается в перемещении Е и его левого поддерева на один уровень вверх и перемещение S и его правого поддерева на один уровень вниз. Остальная часть дерева остается неизменной.

ТОЛЬКО три связи и два узла, которое позволяет перемещать узлы по деревьям, не изменяя глобальные свойства порядка, превращающие BST-дерево в полезную структуру для поиска (см. программу 12.12). Ротации используются для перемещения конкретных узлов по дереву и для предотвращения разба-лансировки деревьев. В разделе 12.9 с помощью ротаций реализованы remove, join и



другие операции с АТД; в главе 13 они будут применяться для построения деревьев, для которых допустима неоптимальная производительность.

Программа 12.12 Ротации в BST-деревьях

Эти две симметричных процедуры выполняют операцию rotation (ротация) в BST-дереве. Ротация вправо делает старый корень правым поддеревом нового корня (старого левого поддерева корня); ротация влево превращает старый корень в левое поддерево нового корня (старого правого поддерева корня). Для реализаций, в которых поле счетчика поддерживается в узлах (например, для поддержки операции select, как будет показано в разделе 14.9), необходимо также обменять поля счетчиков для участвующих в ротации узлах (см. упражнение 12.75).

void rotR(link& h)

{ link X = h->l; h->l = x->r; x->r = h;

h = x; } void rotL(link& h)

{ link X = h->r; h->r = x->l; x->l = h;

h = x; }

Операции ротации обеспечивают простую рекурсивную реализацию вставки в корень: необходимо рекурсивно вставить новый элемент в соответствующее поддерево (оставив его по заверщении рекурсивной операции в корне этого дерева), а затем выполнить ротацию, чтобы сделать узел корнем главного дерева. Пример показан на рис. 12.14, а программа 12.13 содержит реализацию данного метода. Эта программа - убедительный пример больших возможностей рекурсии. Любой читатель, которого это не убеждает, может попытаться выполнить упражнение 12.76.

Программа 12.13 Вставка в корень BST-дерева


РИСУНОК 12.13 РОТАЦИЯ ВЛЕВО В BST-ДЕРЕВЕ

На этой схеме показан результат (внизу) ротации влево узла А в примере BST-дерева (вверху). Узел, содержащий А, перемещается вниз, становясь левым дочерним узлом своего прежнего правого дочернего узла.

Ротация выполняется за счет получения связи с новым корне.м Е из правой связи А, установки правой связи А путем копирования левой связи Е, установки левой связи Е на А и установки связи с А (верхняя связь дерева) вместо этого на Е.

При наличии функций ротации, определенных в программе 12.12, реализация рекурсивной функции, которая вставляет новый узел в корень BST-дерева, очевидна: необходимо вставить новый элемент в корень соответствующего поддерева, а затем выполнить соответствующую ротацию, что приведет к его переносу в корень главного дерева.

private: void insertT (linkfi h, Item x)

{ if (h == 0) { h = new node(x); return; } if (x.keyO < h->item.key 0)

{ insertT(h->l, x); rotR(h) ; } else { insertT(h->r, x) ; rotL(h); }

public: void insert(Item item) { insertT(head, item); }



1 ... 164 165 166 [ 167 ] 168 169 170 ... 225

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика