При построении рандомизированного дерева основное исходное положение заключается в том, что любой элемент может с одинаковой вероятностью быть корнем дерева. Причём это справедливо и для поддеревьев рандомизированного дерева. Поэтому при включении нового элемента в дерево, случайным образом выбирается включение элемента в качестве листа, или в качестве корня. Вероятность появления нового узла в корне дерева или поддерева определяется, как 1/(n+1), где n – число узлов в дереве или в поддереве. То есть, дерево выглядит так, будто элементы поступали в него в случайном порядке. Поскольку принимаемые алгоритмом решения являются случайными, при каждом выполнении алгоритма при одной и то же последовательности включений будут получаться деревья различной конфигурации. Таким образом, несмотря на увеличение трудоёмкости операции включения, за счет рандомизации получается структура дерева, близкая к сбалансированной. Благодаря сбалансированности дерева трудоёмкость в рандомизированном дереве имеет оценку О(log2n) и в среднем операции более эффективны, чем в BST-дереве.
|
|
Рекурсивный алгоритм вставки в рандомизированное дерево:
RND_Insert(t, k, data, inserted)
1. t – корень дерева или поддерева
2. k –ключ нового элемента
3. data – данные нового элемента
4. inserted – возвращаемый признак вставки
5. if t = nil
6. then t ← Create_Node (k, data)
7. n[ t ] ← 1
8. inserted ← TRUE
9. return t
10. if Rand() < RAND_MAX/(n[ t ]+1)
11. then t ← Root_Insert (t, k, data, ins)
12. inserted ← ins
13. return t
14. if k = key[ t ]
15. then inserted ← FALSE
16. return t
17. if k < key[t]
18. then left[ t ] ← RND_Insert (left[ t ], k, data, ins)
19. else right[ t ] ← RND_Insert (right[ t ], k, data, ins)
20. inserted ← ins
21. if inserted = TRUE
22. then n[ t ] ← n[ t ] + 1
23. return t
Поскольку принимаемые алгоритмом решения являются случайными, то при каждом выполнении алгоритма для одной и той же последовательности включений будут получаться различные конфигурации рандомизированного дерева. Таким образом, не смотря на увеличение трудоемкости операции включения, за счет рандомизации получается структура дерева, близкая к сбалансированной.
Поиск в рандомизированном дереве ведется по стандартному алгоритму поиска в BST – дереве. Благодаря сбалансированности дерева в среднем поиск оценивается нотацией O(log2 n) и более эффективен, чем в BST – дереве.
Недостатком приведенного алгоритма являются затраты на генерацию случайных чисел в узлах, лежащих на пути операции включения. Чтобы минимизировать эти затраты, можно вместо системного генератора случайных чисел использовать числа, которые не являются совершенно случайными, но для генерации требуют небольших затрат. Например, функцию Rand() можно заменить проверкой условия 111 mod n[t] = 3 для принятия решения о вставке в корень [4].
|
|
Второй недостаток – необходимость поддержки параметра n[t] в узлах рандомизированного дерева. Но, если этот параметр необходим по другим причинам, например для решения задач о порядковых статистиках, то этот недостаток не является решающим.
· Вставка элемента x во множество. Выполняется так:
Начинаем с корневого узла дерева (его адрес записан в root). Сравниваем x со значением v в этом узле. Если они равны, то мы нашли x и делать ничего не надо – выходим из процедуры. Если x меньше v, то переходим по левому указателю (left), если больше – по правому (right). Продолжаем делать так до тех пор, пока указатель, по которому надо переходить, не окажется NIL. В этом случае создаём новый узел и его адрес помещаем в этот указатель.
И не забываем ещё один нюанс. Если элемент вставляется в пустое дерево, то адрес созданного узла нужно записать в переменную root.
Приведём пример реализации:
procedure ins(var root: PNode; x: integer);
var
r: PNode;
begin
if root=NIL then begin
new(root);
root^.left:=NIL; root^.right:=NIL; root^.v:=x;
exit;
end;
r:=root;
repeat
if r^.v=x then exit;
if x<r^.v then
begin
if r^.left<>NIL then
r:=r^.left
else
begin
new(r^.left);
r:=r^.left;
r^.left:=NIL; r^.right:=NIL; r^.v:=x;
exit;
end
end
else
begin
if r^.right<>NIL then
r:=r^.right
else
begin
new(r^.right);
r:=r^.right;
r^.left:=NIL; r^.right:=NIL; r^.v:=x;
exit;
end;
end;
until false;
end;