Рандомизированное бинарное дерево поиска — различия между версиями
Dima (обсуждение | вклад) м |
Dima (обсуждение | вклад) м |
||
| Строка 1: | Строка 1: | ||
| − | Рандомизированное бинарное дерево поиска (англ. Randomized binary search tree, RBST) {{---}} структура данных, представляющая собой бинарное дерево поиска. | + | Рандомизированное бинарное дерево поиска (англ. ''Randomized binary search tree'', RBST) {{---}} структура данных, представляющая собой бинарное дерево поиска. |
==Основная идея и связанные определения== | ==Основная идея и связанные определения== | ||
Версия 17:30, 1 мая 2012
Рандомизированное бинарное дерево поиска (англ. Randomized binary search tree, RBST) — структура данных, представляющая собой бинарное дерево поиска.
Содержание
Основная идея и связанные определения
Как известно, можно подобрать такую последовательность операций с бинарным деревом поиска в наивной реализации, что его глубина будет пропорциональна количеству ключей, а следовательно запрос будет выполняться за . Поэтому, если поддерживать инвариант "случайности" в дереве, то можно добиться того, что математическое ожидание глубины дерева будет небольшим. Дадим рекурсивное определение рандомизированного бинарного дерева поиска (RBST).
| Определение: |
Пусть — бинарное дерево поиска. Тогда
|
Из определения следует, что каждый ключ в RBST размера n может оказаться корнем с вероятностью 1/n.
Идея RBST состоит в том, что хранимое дерево постоянно является рандомизированным бинарным деревом поиска. Далее подробно будет описана реализация операций над RBST, которая позволит добиться этой цели. Заметим лишь, что хранение RBST в памяти ничем не отличается от хранения обычного дерева поиска: хранится указатель на корень; в каждой вершине хранятся указатели на её сыновей.
(Похожие идеи используются в декартовом дереве, поэтому во многих русскоязычных ресурсах термин рандомизированное бинарное дерево поиска используется как синонимическое название декартового дерева и декартового дерева по неявному ключу)
Операции
Операции обхода дерева, поиска ключа, поиска максимума/минимума, поиск следующего/предыдущего элемента выполняются как в обычном дереве поиска, т.к. не меняют структуру дерева.
Вставка
Рассмотрим рекурсивный алгоритм вставки ключа в RBST, состоящее из вершин. С вероятностью вставим ключ в корень дерева, используя процедуру insert_at_root. С вероятностью вставим его в правое поддереао, если он больше корня, или в левое поддерево, если меньше. Ниже приведён псевдокод процедуры вставки insert, процедуры insert_at_root, а также процедуры split(k), разбивающей дерево на два поддерева, в одном из которых все ключи строго меньше , а в другом больше, либо равны; приведена достаточно очевидная рекурсивная реализация. (через Node обозначен тип вершины дерева, дерево представляется как указатель на корень)
Node insert (T, x)
int r = random(0..size(T))
if (r = n)
T = insert_at_root(T, x)
if (x < root.key)
T = insert(T.left, x)
else
T = insert(T.right, x)
return T
Заметим, что если дерево пусто, то insert с вероятностью 1 делает корнем.
// вставляет ключ x в дерево T Node insert_at_root (T, x) // создать пустые L и R L = RBST() R = RBST() split(T, x, L, R) // создать пустое T T = RBST() T.key = x T.left = L T.left = R return T
// разделяет дерево T по x
// результат: деревья L и R
split (T, x, L, R)
if (size(T) = 0)
// создать пустые L и R
L = RBST()
R = RBST()
else if (x < T.key)
R = T
split (T.left, x, L, R.left)
else
L = T
split (T.right, x, L.right, R)
Далее рассмотрим как меняется свойство дерева быть рандомизированным при вставке в него ключей.
| Лемма: |
Пусть после операции split от дерева по ключу были получены деревья и . Тогда если было рандомизированным бинарным деревом поиска, содержащим множество ключей , то деревья и — рандомизированные бинарные деревья поиска, содержащие соответственно множества ключей и . |
| Доказательство: |
|
Применим индукцию по — размеру дерева. Если , то лемма верна (получим два пустых дерева). Пусть , и лемма верна при всех меньших размерах дерева.. Пусть также . Если , то — корень , — левое поддерево , а split рекурсивно вызовется от , разделив его на — правое поддерево —, и , которые по предположению индукции будут рандомизированными бинарными деревьями поиска. Но также является RBST, т.к. является поддеревом . Итак для того, чтобы доказать, что — рандомизированное бинарное дерево поиска, осталось показать, что любая его вершина с вероятностью окажется в корне, где — размер . Действительно: (пусть событие — является коренем ) Случай, когда симметричен рассмотренному. |
| Теорема: |
Если — рандомизированное бинарное дерево поиска, содержащее множество ключей , , тогда процедура insert(x, T) вернёт рандомизированное бинарное дерево поиска , содержащее множество ключей . |
| Доказательство: |
|
Применим индукцию по — размеру дерева. Если , то теорема верна: после операции insert(x, T) получим дерево с корнем и двумя пустыми поддеревьями. Пусть , и теорема верна при всех меньших размерах дерева. Возможны два случая: вставляется в корень или рекурсивно в одно из поддеревьев. В первом случае правое и левое поддеревья по лемме являются рандомизированными BST, а также вероятность того, что окажется в корне, равна . Т.е. новое дерево — рандомизированное BST. Во втором случае корень у дерева останется прежнем. Заметим, что для каждого вероятность быть корнем была , а корнем он останется с вероятностью , тогда для каждого вероятность быть корнем равна . По предположению же индукции поддерево, в которое вставляется становится рандомизированным бинарным деревом поиска; а т.к. другое поддерево корня было рандомизированным, то новое дерево — рандомизированное BST. |
Пусть — множество ключей, — какая-то фиксированная перестановка элементов . Из приведённой выше теоремы следует, что если в изначально пустое дерево добавлять ключи P по порядку, то получим дерево , являющееся RBST.
Удаление
Алгоритм удаления использует операцию merge — слияние двух деревьев, удовлетворяющих условию: все ключи в одном из деревьев меньше ключей во втором. Для того, чтобы удалить некоторый ключ из RBST сначала найдём вершину с этим ключом в дереве, используя стандартный алгоритм поиска. Если вершина не найдена, то выходим из алгоритма; в противном случае сливаем правое и левое поддеревья (заметим, что ключи в левом поддереве меньше ключей в правом), удаляем , а корень образовавшегося дерева делаем новым сыном родителя . Псевдокод процедур удаления и слияния приведён ниже.
// удаляет ключ x из дерева T
Node remove(T, x)
if (size(T) = 0)
// выйти, вернув пустое дерево
T = RBST()
return T
if (x < T.key)
T.left = remove(T.left, x)
else if (x > T.key)
T.right = remove(T.right, x)
else
// создать пустое дерево Q
Q = RBST()
Q = merge(T.left, T.right)
T = Q
return T
// сливает деревья L и R
// результат: дерево T
Node merge(L, R)
int m = L.size
int n = R.size
int total = m + n
if (total = 0)
// вернуть пустое T
T = RBST()
return T
int r = random(1..total)
if (r < m)
// с вероятностью m / (m + n)
L.right = merge(L.right, R)
return L
if (r < m)
// с вероятностью m / (m + n)
R.left = merge(L, R.left)
return R
Докажем, что данный алгоритм оставляет рандомизированное дерево рандомизированным.
| Лемма: |
Пусть и — рандомизированные бинарные деревья поиска, содержащие соответственно множества ключей и , причём (то есть каждый элемент меньше каждого элемента ). Тогда операция merge(L, R) вернёт рандомизированное бинарное дерево поиска, содержащее множество ключей = . |
| Доказательство: |
|
Пусть и — размеры и соответственно. Применим индукцию по и . Если или , то лемма верна. Пусть и , пусть также или . Без потери общности делаем корнем . После рекурсивного слияния правого поддерева и получим рандомизированное бинарное дерево поиска (которое является правым поддеревом нового дерева). Левое же поддерево нового дерева тоже рандомизированное. Также верно, что для любого вероятность быть корнем равна : действительно, вероятность оказаться в корне в до слияния равна , вероятность того, что элемент останется корнем после слияния равна ; осталось применить правило умножения. |
| Теорема: |
Если — рандомизированное бинарное дерево поиска, содержащее множество ключей , тогда процедура remove(x, T) вернёт рандомизированное бинарное дерево поиска , содержащее множество ключей |
| Доказательство: |
|
Если удаляемый элемент отсутствует в дереве, то теорема верна. Пусть (дерево не пусто), — размер . Докажем теорему по индукции по . Для теорема очевидным образом верна. Пусть , и предположим, что теорема верна для всех деревьев размера меньше . Возможно два случая: если — корень , то по лемме, после удаления получим рандомизированное бинарное дерево поиска; если же — не корень , то рекурсивно удаляется из поддерева исходного дерева, и по предположению индукции после удаления получаем рандомизированное BST. Осталось лишь показать, что для любого вероятность оказаться корнем после удаления равна . Введём обозначения: событие — является коренем ; событие — был корнем (до операции remove); событие — стал корнем после операции merge (но до этого им не являлся); событие — был корнем (до операции remove); Тогда: . |
Анализ времени работы
Достаточно очевидно, что время работы приведённых алгоритмов пропорционально глубине дерева. Но т.к. математическое ожидание глубины рандомизированного бинарного дерева поиска есть , где — число вершин в дереве, то математическое ожидание времени работы поиска, вставки и удаления — также .
См. также
Ссылки
Литература
- Martinez, Conrado; Roura, Salvador (1997), "Randomized binary search trees", Journal of the ACM 45
- Seidel, Raimund; Aragon, Cecilia R. «Randomized Search Trees», 1996 г.
- Randomized binary search trees. Lecture notes from a course by Jeff Erickson at UIUC.