Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
algorithms.doc
Скачиваний:
29
Добавлен:
06.12.2018
Размер:
9.73 Mб
Скачать
      1. Добавление элемента в дерево

Требуется добавить в дерево вершину v.

Для этого ищем лист, после которого следует вставить v и вставляем v после него.

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

STree *Insert(STree *root, STree *v)

{

if(v->value>=root->value)

return root->right==NULL ?

(v->back=root,v->right=v->left=NULL,root->right=v) : Insert(root->right, v);

else

return root->left==NULL ?

(v->back=root,v->right=v->left=NULL,root->left=v) : Insert(root->left, v);

}

Отметим, что здесь активно используется разделитель выражений – запятая. Напомним, что, если несколько арифметических выражений в языке С разделены запятой, то значение всего выражения равно последнему из них.

      1. Поиск минимального и максимального элемента в дереве

STree *SearchMin(STree *root)

{ return root->left==NULL?root: SearchMin(root->left);}

STree *SearchMax(STree *root)

{ return root->right==NULL?root: SearchMin(root-> right);}

      1. Удаление элемента из дерева

Удаление вершины v из дерева поиска не представляет проблем, если данная вершина является листом или имеет всего одного потомка. Иначе, например, из правого поддерева v можно изъять минимальный элемент (самый левый) и поместить его на место удаленного. При этом, дерево останется деревом поиска.

      1. Поиск следующего/предыдущего элемента в дереве

Если у текущего элемента v есть правый потомок, то следующим элементом будет минимальный элемент в поддереве, которое имеет корень v->right. Иначе мы должны подниматься вверх по дереву, пока не встретиться вершина v, являющаяся левым потомком своего родителя. В этом случае родитель этой вершины будет следующим элементом дерева.

STree *SearchNext(STree *cur)

{

if(cur==NULL)return NULL;

if(cur->right!=NULL)return SearchMin(cur->right);

while(cur->back && cur!=cur->back->left)cur=cur->back;

return cur->back;

}

Аналогично ищется предыдущий элемент.

      1. Слияние двух деревьев

Для двух деревьев поиска T1 и T2 таких, что все элементы в T1 меньше или равны всех элементов в T2 : слияние деревьев в одно дерево поиска T.

Выбираем из дерева T2 наименьший элемент (самый левый), исключаем его из дерева T2 и делаем его корнем нового дерева T. Его левым потомком будет корень дерева T1, а правым – корень дерева T2 . Дерево T будет деревом поиска.

Далее нам встретится немного другая задача – пусть задан некоторый элемент v и два дерева T1 и T2 такие, что все элементы в T1 меньше или равны v, а все элементы из T2 - больше или равны. Слить все указанные данные в одно дерево поиска T. Элемент v, в этой ситуации, называется стыковочным. Задача в данной формулировке тривиальна.

      1. Разбиение дерева по разбивающему элементу

Для данной вершины дерева v разбиение дерева поиска T на два дерева поиска T0 и T1 таких, что все элементы в T0 меньше v, и все элементы в T1 больше или равны v.

Для наглядности рассуждений расположим геометрически дерево поиска таким образом, чтобы вершины были упорядочены по оси OX. Проведем на графике из вершины v вертикальную линию. Все элементы в дереве слева от этой линии – меньше или равны v, а справа – больше или равны.

Вершина v имеет два поддерева, из нее выходящих, в одном из которых все элементы меньше v , а в другом – больше или равны. Назовем эти деревья T0 и T1 , соответственно.

Вершины ветви, от v до корня дерева r назовем V’ = {v1=v,v2,v3,…,vn=r }.

Поддерево, выходящее из вершины, являющейся потомком vi V , назовем Ti (см. рисунок выше).

Легко доказать, что верны следующие факты для любого i:

либо для любого j<i: Ti < vi Tj , Ti < vi vj (vj правому поддереву vi),

либо для любого j<i: Ti vi > Tj , Ti vi > vj (vj левому поддереву vi).

Легко увидеть, также, что все дерево T состоит из вершин, принадлежащих либо некоторому Ti , либо V.

Итак, конструирование двух требуемых поддеревьев будем производить следующим способом. Рассмотрим, сначала поддеревья T0 и T1. Будем последовательно добавлять в них данные, чтобы получить искомые деревья.

Будем далее последовательно перебирать вершины vi для i от 2 до n.

На каждом шаге если vi vi-1, то Ti< vi T0 и мы сливаем деревья Ti и T0 c с помощью стыковочного элемента vi. Иначе vi > vi-1 , тогда Ti vi> T1 и мы сливаем деревья Ti и T1 c с помощью стыковочного элемента vi .

В силу вышесказанного, в конечном итоге, деревья T0 и T1 будут искомым разбиением исходного дерева поддеревья T с помощью вершины v.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]