
сиаод / Reformating_Saod
.pdfЗатраты операций пропорциональны высоте дерева. Удаление: возможны 3 случая. 1.удаляемая вершина не имеет сыновей.
2.удаляемая вершина имеет 1-ого сына.
3.вершина имеет 2-х сыновей.
Delete(T,k).
1.if T<> nil then if k<T^.key then Delete(T^.left,k) 2.else if k>T^.key then Delete(T^.right,k)
3.else если узел не имеет сыновей:
4.if (T^left=nil) and (T^.right=nil) then q:=T;T:=nil; Dispose(q). 5.else если узел имеет сыновей:
6.else if (T^.left=nil) then q:=T; T:=T^.right; Dispose(q). 7.else (if T^.right=nil) then q:=T; T:=T^.left; Dispose(q). 8.else Del(T^.right,T).
Del(T,q), T-ук-ль на корень дерева, q-ук-ль на замен-ю вершину.
1.if T^.left=nil then q^.keyT^.key; q1T TT^.right 2.Dispose(q1); return
3.else Del(T^.left, q).
Представление 2-ых деревьев с помощью ук-лей: узлы дерева опр-ся как переменные с фикс. Структурой, а связи м-ду ними с помощью УК-лей. Т.к. степень дерева=2, то число УК-лей тоже 2. Ссылка на пустое поддерево – nil.
Type pNode=^Node; Node=record Info:T0; left, right:pNode
End;
26. Добавление элемента в двоичном дереве поиска.
Заметим, что параметр Р передается как параметр-переменная, а не как параметрзначение. Это существенно, т.к. ей присваивается новое значение ссылки.
С учетом этого, а также считая, что ключи слов читаются из файла INPUT, основную программу можно записать:
BEGIN ROOT := Nil;
WHILE NOT EOF DO BEGIN READ (K);
SEARCH (K, ROOT); END;
PRINTTREE (ROOT, 0) END.
Переменные ROOT и K должны быть описаны как
VAR ROOT: REF; K: INTEGER;
Пусть типы описаны следующим образом:
TYPE REF = ^WORD; WORD = RECORD KEY: INTEGER; COUNT: INTEGER; LEFT, RIGHT: REF END;
Считаем, что есть исходный файл ключей F, а переменная ROOT указывает на корень дерева поиска.

27. Удаление элемента в двоичном дереве поиска.
Удаление – задача, обратная включению. Нужно построить алгоритм для удаления узла с ключом Х из дерева с упорядоченными ключами. Удаление элемента обычно не так просто, как включение. Оно просто в случае, когда удаляемый элемент является терминальным узлом или имеет одного потомка
Трудность возникает при удалении элементов с двумя потомками, т.к. мы не можем указывать одной ссылкой на два направления. В этом случае удаляемый элемент надо заменить либо на самый правый элемент его левого поддерева, либо на самый левый элемент его правого поддерева. Ясно, что такие элементы не могут иметь более одного потомка
Процесс удаления можно представить рекурсивной процедурой DELETE. Она различает три случая:
1)компоненты с ключом, равным Х, нет;
2)компонента с ключом Х имеет не более одного потомка;
3)компонента с ключом Х имеет двух потомков.
PROCEDURE DELETE (X: INTEGER; VAR P: REF); VAR Q: REF;
PROCEDURE DEL(VAR R: REF); BEGIN
IF R^.RIGHT <> NIL THEN DEL(R^.RIGHT)
ELSE BEGIN Q^.KEY := R^.KEY; Q^.COUNT := R^.COUNT; Q := R; R := R^.LEFT END
END { DEL } BEGIN { DELETE }
IF P = NIL THEN WRITELN(' нет слова с заданным ключом ') ELSE
IF X < P^.KEY THEN DELETE(X, P^.LEFT) ELSE
IF X > P^.KEY THEN DELETE (X, P^.RIGHT)
ELSE BEGIN { удаление по указателю Р }
Q := P;
IF Q^.RIGHT = NIL THEN P := Q^.LEFT ELSE
IF Q^.LEFT = NIL THEN P := Q^.RIGHT ELSE DEL(Q^.LEFT); DISPOSE(Q)
END
END { DELETE }
Вспомогательная рекурсивная процедура DEL вызывается только в третьем случае. Она "спускается" вдоль самой правой ветви левого поддерева удаляемого узла Q^ и затем заменяет существующую информацию (ключ и счетчик) в Q^ соответствующими значениями самой правой компоненты R^ этого левого поддерева, после чего от R^ можно освободиться. Это делается с помощью стандартной процедуры DISPOSE(Q).
28. Абстрактная таблица. Основные операции. Способ реализации.
Элементы АТ обычно записи, содерж неск-ко полей. Для идентиф эл-тов исп-ся ключи поиска.
Основные операции над АТ 1.Создать пустую 2.Уничтожить Т 3.Пуста ли
4.Определ кол-во элем в табл
5.Вставить нов элем
6.Удалить элем по заданному ключу
7.Извлечь элем по заданному ключу
8.Обойти элем в порядке следования их ключей Реализация:
Линейная Неупорядоченный массив
Неупорядоч связный список Упорядоч массив упорядоч связный список
Нелинейная (Бин Дер П_) дает ряд преимуществ над линейной. Если дерево имеет min высоту (оценивается [log2(n+1)], то оно позволяет выполнить когда лин стр-ры неприменимы.
29. Сбалансированные деревья поиска.
29,30. AVL-деревья. Свойства. Вращение.
Для каждого узла высота его поддеревьев различается не более чем на 1. Все операции аналогины операциям над БДП за исключением вставки и удаления узла, т.к.необходимо сохранение сбалансированности. Для хранения инфы о сбалансированности вводят дополнительное поле (Balance), указывающее какое поддерево длиннее( leftheavy, rightheavy, balanced).
TBalance=( leftheavy, rightheavy, balanced); TAVLTree=^AVLNode;
AVLNode=record
Key:integer;
Left, right: TAVLTree; Balance:TBalance; End;
После вращения древо должно обладать след св-ми 1.Прохождение в симметричном порядке должно оставаться таким же как в первоначальном 2.Дерево должно быть сбалансированным.
Левое вращение
Child<-Parent.right Parent.right<-child.left Child.left<-Parent Parent.Balance<-Balanced Parent<-Child Parent.Balance<-Balanced
Вращение вправо-влево
Child<-parent.right GrandChild<-Child.left; Child.left<-GrandChild.right

GrandChild.right<-Child;
Parent.right<-GrandChild.left;
GrendChild.left<–parent;
If GrandChild.Balance=RightHeavy then
Parent.balance<-leftHevy
Else Parent.balance<-balanced
If GrandChild.Balance=leftHeavy then Child.balance<-rightHevy
Else child.balance<-balanced
Parent<=GrandChild
Parent.balance<-balanced;
31. Добавление вершины в AVL-дерево.
1.Следовать по пути поиска, пока не окажется, что ключа нет в дереве
2.Включит новый узел и определить новый показатель сбалансированности
3.Пройти обратно по пути поиска и проверить Balance для каждого узла
4.Найти место вставки нового узла и вставить
5.Если вставили в левое поддерево, то
6.Если правое было длиннее, то стало сбалансированным
7.Если были равны, то левое выросло, данное поддерево сбалансировано, надо проверить баланс выше.
8.Если левое было длиннее, оно ещё выросло, поэтому имеем сбаланс-ое дерево слева. Необходимо произвести вращение для перебалансировки.
Если вставили в правое , то то же самое, но наоборот.
32. Удаление вершины в AVL-дереве.
Удаляем Т1. Правое поддерево точно сбалансировано, либо его правая половина на 1 >, тогда левое вращение перебалансирует дерево( В-корень, х-его левый сын, Т1 и Т2 его сыновья, Т3 правый сын В)
Возможны 2 случая 1)поддерево Тв точно сбалансировано – после вращения глубина не изменится, дерево выше сбансировано.
2)Глубина уменьшилась на 1, дерево выше может быть разбалансировано, надо проверить дерево, чтобы сохранялись AVL свойства
d
end
33. Красно-черные деревья. Свойства. Вращение.
КЧД – бинарное дерево поиска, каждая вершина которого хранит один дополн бит – цветкрасный или чёрный. Каждая вершина кр-ч дерева имеет поля(key, colour,left,right,parent). Зн-я nil, хранящиеся в полях кр и ч явл-ся ссылками. БДП наз-ся кр-ч деревом, если:
Свойства 1.Каждая вершина – красная либо черная
2.корень дерева - чёрный
3.Каждый внешний лист – черный
4.Если вершина красная, то её сыновья черные 5.Все пути, ведущие от корня к внешним листьям, имеют одинаковое число черных вершин.
34. Добавление вершины в красно-черном дереве.
Добавление вершины в красно-черное дерево производится за время O(log n). Сначала спустимся вниз по дереву, так как это происходит при поиске, пока мы не окажется в вершине не имеющий сына. Добавим вершину x с той стороны, куда мы должны были бы двинуться, если бы вершина имела детей. Красим новую вершину в красный цвет. После этого надо восстановить свойства красно-черного дерева, для чего приходится перекрасить некоторые вершины и произвести вращения.
После добавления вершины выполняются все свойства красно-черного дерева, кроме одного: красная вершина x может иметь красного родителя, и это нарушение единственно. Восстанавливается это свойство очень просто: пока вершина x не корень дерева и имеет красного родителя выполняем следующие действия: если дядя вершины x красного цвета, то красим его и отца вершины x в черный цвет, а дедушку вершины x в красный цвет. Далее вершиной x становится дедушка. Если дядя вершины х черного цвета, то проверяем являются ли вершина x и его отец одинаковыми детьми (т.е. оба ЛЕВЫЕ или ПРАВЫЕ дети). Если не являются одинаковыми детьми, то делаем соответствующие вращение (становятся одинаковыми детьми). Красим отца в черный цвет. Далее делаем соответствующее вращение;
RB-Insert Tree-Insert(T,x) Color[x]<-red
While x<>root[T] and color [p[x]]=red do begin If p[x]=left[p[p[x]]] then begin Y<-right[p[p[x]]]
If color[y]=red then begin Color[p[x]]<-black Color[p[y]]<-black Color[p[p[x]]]<-red X<-p[p[x]]
End else begin
If x=right[p[x]] then begin X<-p[x]
Left-rotate(T,x) End;
End else
{аналогично с заменой left<->right} color[root[T]]<-black
35. Удаление вершины в красно-черном дереве.
Для начала находим вершину z в дереве, которую требуется удалить. Возможны три случая:
1.если у вершины z нет детей, для удаления z достаточно поместить NIL в соответствующее поле его родителя (вместо z).
2.если у z один ребенок, то можно вырезать z, соединив его родителя напрямую с его ребенком.
3.если у z двое детей, то мы находим следующий (в смысле порядка на ключах) за z элемент y; у него нет левого ребенка. Теперь можно скопировать ключ и дополнительные данные из вершины y в вершину z, а саму вершину y удалить выше описанным способом. Если была удалена черная вершина, то надо восстановить свойства красно-черного дерева (при удалении красной вершины свойства дерева не нарушаются). Пусть вершина x - ребенок удаленной вершины. Пока вершина x не корень дерева и она чёрная вершина выполняем следующие действия:если у вершины x брат красного цвета, то делаем
ВРАЩЕНИЕ (брат становится родителем отца), при этом брата красим в черный, а отца в красный;если у вершины x брат чёрного цвета, то: если у брата оба ребенка черные, то красим брата в красный цвет. Теперь вершиной x будет его отец. Если у брата его "одинаковый" ребёнок черного цвета, то красим брата в красный цвет и делаем вращение. Иначе красим брата в цвет отца, отца красим в черный цвет. Делаем вращение и выходим из цикла.
RB-Delete(T,z)
If (left[z]=nil[T]) or ( right[z]=nil[T]) Then y<-z
Else y<-Tree-Successor(z) If left[y]<>nil[T]
Then x<-left[y] Else x<-right[y] P[x]<-p[y]
If p[y]=nil[T] Then root[T]<-x Else if y=left[p[y]] Then right[p[y]]<-x If y<>z
Then key[z]<-key[y]
{копир остальные данные из y} if color[y]=Black
then RB-Delete-Fixup(T,x) return y RB-Delete-Fixup(T,x)
While (x<>root[T]) and color[x]=black do If x=left[p[x]]
Then begin w<-right[p[x]] If color[w]=red
Then begin color[w]<-black Color[p[x]]<=red Left-rotate(T,p[x])
End
If (color[left[w]]=black) and (color[right[w]]=black) Then color[w]<-red
X<-p[x] Else begin
If color[right[w]] =black
Then begin color[left[w]]<-black Color[w]<-red
Right-rotate(T,x)
End Colo[w]<-color[p[x]] Color[p[x]]<-black Color[right[w]]<-black Left-rotate(T,p[x]) X<-root[T]
End End else
{left<->right то же самое} color[x]<-black
Если удаленная вершина была черной. То любой проходивший через неё путь стал на 1 черную верш короче. Можем компенсировать это за счет вершины x, занявшей место удал верш y. Если x-красная сделаем её чёрной, если черня, объявим её дважды черной. От такой вершины надо избавляться. RB-Delete-Fixup(T,x) применяется к дереву, обладающему св-ми КЧД с учетом дважды черной вершины и превращает его в КЧД
O(log2n).
36. 2-3 деревья. Основные свойства. Обход 2-3 дерева.
Если главный внутренний узел имеет либо 2, либо 3 дочерних узла. Узел, имеющий 2 дочерних узла – двухместный, 3-и дочерних узла – трёхместный. Т.к. внутренние узлы могут иметь 3-и дочерних узла дерево может содержать больше узлов чем БД той же высоты кол-во узлов 2-3-дерева высотой h всегда >= кол-ву узлов БД той же высоты.
Type pNode=^Node; Node=record; S,L: integer; left, middle, right: pNode; end;
Обход 2-3 Д: можно обойти в порядке следования ключей(симметричный обход БД).
Inorder(R: pNode);
1.if (R - явл-ся листом) then обработать Эл-ты этого узла.
2.else if (R – содержит 2-а эл-та) then begin
3.inorder(R.left) обр-ть 1-ый эл-т узла;
4.inoredr(r.middle) обр-ть 2-ой эл-т.
5.inorder(R.right)
6.end
7.else begin inorder(R.left) – обр-ть эл-т узла
8.inorder(R.right)
9.end.
37. Добавление элемента в 2-3 дерево.
1.Найти лист на к-ом прекращается поиск этого Эл-та.
2.Вставка в этот лист при этом: если лист после вставки будет сод-ть только 2-а Эл-та данных, на этом процесс вставки заканчивается, если лист сод-ит 3 эл-та, то это нарушение сво-ва 2-3 дерева. Для восстановл-я сво-в вып-ют преобразование «разделение». Разделение листа в 2-3 дереве: вставить рисунок!!!
Insert (R: pNode; new_elem: TypeElem).
1.S.key key принадлежит New_elem;
2.Leaf_Node. 3. Leaf_NodeNew_elem.
4.if (Leaf_Node содерж 3-и Эл-та) then spit(Leaf_Node). Spit (n: pNode).
1.if (n явл-ся root) then 2. New(p) 3. назнач p родителем узла n. 4. end if.
5.заменить узел n узлами n1 и n2. 6. записать в узел n1S. 7. n2L.
8.if (n не явл-ся листом) then 9. уст-ть n1 род-ем a, b.
10.уст-ть n2 родит-ем c, d. 11. end if. 12. переместить в P{родит узел}M.
13.if (P сод-ит 3-и Эл-та) then 14. Spit (P).
38. Удаление элемента в 2-3 дереве. Алг-м удаления: вставить рисунок!!!
Delete (R:pNode; S_key: Typekey)
1. найти позицию Эл-та ключ кот-ого = S_key. 2. удалить корень.
3. else 4. назн-ть p – родит узла. 5. if (брат узла n сод-ит 2-а Эл-та) then
6. перераспр-е Эл-ов. 7. if (n внутр узел) then 8. переместить дочерний узел к узлу n. 9. else 10. переместить узел из p в доч узел S. 11. if (n – внутр узел) then
12. присоед-ть дочерн узел n к узлу S. 13. удалить n. 14. if (P – пустой) then 15. fix(P); 16. end if. 17. end if.
39. 2-3-4 деревья. Основные свойства.
Узел может быть 2-х, 3х и 4-х местным.
1.2-х местный узел – рисунок!!!
2.3-х местный узел
3.4-х местный узел
4.узел содержит 1-2-3 эл-та данных.
Type Node = ^pNode pNode = record key: TypeT0; left, leftmiddle, rightmiddle, right: pNode. End.
Поиск проводится как и в 2-3 дереве.
41. Сортировка. Стратегии внутренней сортировки.
Вспомним задачу сортировки в общем виде. Даны элементы a1 , a2 ,..., an . Сортировка означает перестановку этих элементов в порядке ak1 , ak2 ,..., akn , так что при заданной функции
упорядочения справедливо отношение f (ak1 ) f (ak2 ) ... f (akn ) .
1)Выборка – выбирают наименьший элемент и помещают в текущую позицию в выходном потоке.
2)Включение – элементы орабатываются по одному в произв порядке, вставка нового Элта в соотв с отношением его к уже имеющимся 3)Обмен – Эл-ты сравниваются и при необходимости меняются местами пока не будут упорядочены.
4)Распределение – Эл-ты распределяются по подмножествам (младшие – в одно, старшие
– в другое, промежуточные – в промеж)
5)Слияние – сортироанные подмножества объединяются в более крупные, исп-я методы слияния.
42. Турнирная сортировка.
строится двоичное дерево (глубина 2к≥n) сортируемых ключей: 1.все ключи листья
2.из пар выбирается мин и становится узлом порядка k-1, процесс продолжается пока корнем дерева не станет мин эл-т 3.переправляем этот эл-т в исходную последовательность
4.спускаемся по дереву и заменяем значения мин элемента на + 5.все промежуточные узлы заменяем мин из оставшихся.
6.процесс продолжается до тех пор пока все листья не будут заменены фиктивными ключами
число сравнений (n-1)log2n: время работы O(log2n)
43. Пирамидальная сортировка.
Метод простого выбора. N(n-1) сравнений, n-1 перестановок. Пирамидальная сортировка (сложность nlogn, неустойчивый алгоритм)
Дерево наз-я пирамидально упорядоченным, если ключ в каждом его узле >= ключам всех его потомков.Сортирующее дерево – совокупность ключей, образующих полное пирамидально упорядоченное дерево. Для реализации дерева исп-ся массив([i|2]-родитель, 2i, 2i+1- потомки). При такой организации прохождение по дереву проходит более быстро с большой экономией памяти. Поддержание осн св-ва пирамид дерева.
Heapify(A,i)
L:=left[i]
R:=right[i]
If l =< Heap-Size(A) &A[l]>A[i] Then largest:=l
Else largest:=к
If (r=<Heap-Size(A) & (A[r]>A[largest) Then largest:=к
If largest<>I then begin A[i]<–>A[largest] Heapify(A,largest) End
Построение пирамиды
Build-Heap(A) Heap-Size:=length(A)
For i:=[length(A)/2] downto 1 do Heapify(A,i)
Сортировка
HeapSort Build-Heap(A)
Fori:=length(A) downto 2 do A[1]<->A[i] Heap-Size(A):=Heap-Size(A)-1 Heapify(A,1)
44.Вставка с убывающим шагом (метод Шелла).
Простая вставка n2/4 – вычислит сложность.
Рассм пары с шагом h/2, если элем не упорядочены, то меняем их местами
рассм группы с шагом h|4 выполняем сортировку в группах
уменьшаем шаг и т.д. Проходим по всему массиву. Выч сложность O(n(logn)2) ShellSort(x,n,hs,s)
For i:=s downto 1 do H:=hs
For j:=h+1 to n do begin Y:=x[j]
k:=j-h
while (k>=1) and (y<x[k]) do begin x[k+h]:=x[k]
k:=k-h end x[k+h]:=y end
end;
45.Быстрая сортировка.
Выбирается опорный Эл-т и все элты делятся, затем повтор для подмножеств.
QuickSort(A,first, last) If first<last then Q<–Partition(A,first,last) QuickSort(A,first, q) QuickSort(A,q+1, last) Partition
X<-A[first]
I<-first-1;
J<-last+1
While true do Repeat j<-j-1 untilA[j]=<x Repeat i<-i+1 untilA[j]>=x
if i<j then A[i}<–>A[j] else rerurn j;
46. Быстрая двоичная сортировка.
1.последовательно вставляем элементы исходно массива в БДП
2.выполняем симметричный обход сформированного дерева 3юпри посещении узлов – копируем содержимое в выходной массив O(log2n) – лучший O(n) – худший O(nlog2n) – вставок эл-тов
Минус – повышенные требования в объему памяти
47. Цифровая сортировка.
будем двигаться по цифрам ключа с права на лево при этом эл-ты сортируемого множества будут распределяться на подмножества в зависимости от цифры ключа 1.создаем очереди на все цифры 2.упорядочиваем по последней цифре числа 310 3.выписываем в массив
4.продолжаем сортировку, пока не пройдем все разряды. 2n-операций.
48. Карманная сортировка.
для значений от 0 до 1
1.создаем массив списков В[0..m-1]
2.заносим эл-ты в списки
3.сортируем списки
4.выписываем эл-ты из списков
O(n) – т.к. данные равномерно распределены в N промежутках, то списки будут примерно равны.
49. Сортировка подсчётом.
если любой из элементов последовательности – целое положительное число в известном диапазоне. Заранее известное число К – макс значение для ключей сорт последовательности. Для каждого эл-та подсчитывается сколько эл-тов входной последовательности меньше К. после этого К напрямую записывается на то место, где оно должно быть.
50. Сортировка слиянием. Рекурсивный алгоритм.
Поскольку на каждом проходе длина подпоследовательности Р удваивается и сортировка заканчивается, как только Р >= N, она требует log2 N проходов. При каждом проходе (по определению) все множество из N элементов копируется ровно один раз. Следовательно, общее число пересылок равно M = N * log2 N. Число сравнений C ключей еще меньше, т.к. при копировании остатка последовательности сравнения не производятся. Но это не слишком важно, поскольку основное время при работе с внешними устройствами