Реализации алгоритмов/АВЛ-дерево: различия между версиями

Содержимое удалено Содержимое добавлено
оформление ссылки на Википедию
м <source> -> <syntaxhighlight> (phab:T237267)
Строка 9:
то имеем оценку на высоту АВЛ-дерева <math>h = O(log(n))</math>, где <math>n</math> — число узлов. Следует помнить, что <math>O(log(n))</math> — [[wikt:мажоранта|мажоранта]], и её можно использовать только для оценки (Например, если в дереве только два узла, значит в дереве два уровня, хотя <math>log(2)=1</math>). Для точной оценки глубины дерева следует использовать пользовательскую подпрограмму.
 
<sourcesyntaxhighlight lang="delphi">
function TreeDepth(Tree : TAVLTree) : byte;
begin
Строка 17:
result := 0;
end;
</syntaxhighlight>
</source>
 
Тип дерева можно описать так
<sourcesyntaxhighlight lang="delphi">
TKey = LongInt;
TInfo = LongInt;
Строка 35:
end;
TAVLTree = PAVLNode;
</syntaxhighlight>
</source>
 
AVL-условия можно проверить так
<sourcesyntaxhighlight lang="delphi">
function TestAVLTree(V:PAVLNode):integer; //возвращает высоту дерева
var a,b:integer;
Строка 53:
Result:=1+max(a,b);
end;
</syntaxhighlight>
</source>
 
== Балансировка ==
Строка 68:
Данное вращение используется тогда, когда (высота b-поддерева — высота L) = 2 и высота c-поддерева > высота R.
<sourcesyntaxhighlight lang="delphi">
//Функция для устранения правого нарушения с помощью вышеописанных поворотов,
//возвращает True если высота дерева уменьшилась, False - если осталась той же
Строка 114:
end;
end;
</syntaxhighlight>
</source>
 
3.'''Малое правое вращение'''
Строка 124:
Данное вращение используется тогда, когда (высота b-поддерева — высота R) = 2 и высота c-поддерева > высота L.
 
<sourcesyntaxhighlight lang="delphi">
//Функция для устранения левого нарушения с помощью вышеописанных поворотов,
//возвращает True если высота дерева уменьшилась, False - если осталась той же
Строка 167:
end;
 
</syntaxhighlight>
</source>
В каждом случае достаточно просто доказать то, что операция приводит к нужному результату и что полная высота уменьшается не более чем на 1 и не может увеличиться.
 
Строка 190:
 
вспомогательная функция сравнивающая два ключа
<sourcesyntaxhighlight lang="delphi">
function KeyCompare(const V1,V2:TKey):integer;
begin
Строка 201:
Result:=1;
end;
</syntaxhighlight>
</source>
Рекурсивная процедура вставки:
<sourcesyntaxhighlight lang="delphi">
function AVL_InsertNode(Var Tree : TAVLTree; const aKey : TKey; const ainfo : TInfo): Boolean;
Var
Строка 237:
end;
end;
</syntaxhighlight>
</source>
 
== Алгоритм удаления вершины ==
Строка 245:
 
Упрощённый вариант удаления можно описать таким образом
<sourcesyntaxhighlight lang="delphi">
// Функция очень далека от оптимальной,
// сравнение происходит даже после нахождения удаляемого ключа
Строка 298:
end;
end;
</syntaxhighlight>
</source>
Докажем, что данный алгоритм сохраняет балансировку. Для этого докажем по индукции по высоте дерева, что после удаления некоторой вершины из дерева и последующей балансировки высота дерева уменьшается не более, чем на 1. База индукции: Для листа очевидно верно. Шаг индукции: Либо условие балансированности в корне (после удаления корень может изменится) не нарушилось, тогда высота данного дерева не изменилась, либо уменьшилось строго меньшее из поддеревьев => высота до балансировки не изменилась => после уменьшится не более чем на 1.
 
Строка 310:
 
 
<sourcesyntaxhighlight lang="delphi">
type
PAVLTree = ^TAVLTree; //дополнительный тип для указания на место, где хранится указатель на лист
Строка 373:
Result := true;
end;
</syntaxhighlight>
</source>
 
== Нерекурсивное удаление из АВЛ-дерева сверху вниз ==
Строка 380:
# высота дерева по направлению движения меньше противоположной(«брат» направления) и баланс «брата» равен 0 (разбор этого варианта довольно сложен, так что пока без доказательства)
 
<sourcesyntaxhighlight lang="delphi">
function AVL_DropNode2(var Root : PAVLNode; const Key : TKey): Boolean;
var PrimeNode, p, q, b : PAVLTree;
Строка 456:
Dispose(DroppedNode);
end;
</syntaxhighlight>
</source>
Для облегчения понимания приведённый алгоритм не содержит каких-либо оптимизаций. В отличие от рекурсивного алгоритма, найденная удаляемая вершина заменяется значением из левой подветви. Этот алгоритм можно оптимизировать так же, как и рекурсивный (за счёт того, что после нахождения удаляемой вершины известно направление движения):
# ищем удаляемый элемент и попутно находим нашу замечательную вершину