Дерево ван Эмде Боаса — различия между версиями
Warrior (обсуждение | вклад) (→Структура) |
|||
Строка 7: | Строка 7: | ||
Особенностью этой структуры является то, что все операции выполняются за <tex>O(\log k)</tex>, что асимптотически лучше, чем <tex>O(\log n)</tex> в большинстве других деревьев поиска, где <tex>n</tex> {{---}} количество элементов в дереве. | Особенностью этой структуры является то, что все операции выполняются за <tex>O(\log k)</tex>, что асимптотически лучше, чем <tex>O(\log n)</tex> в большинстве других деревьев поиска, где <tex>n</tex> {{---}} количество элементов в дереве. | ||
− | = Структура = | + | == Структура == |
[[Файл:Дерево_ван_Эмде_Боаса.png|right|570px|thumb|4-дерево, содержащее в себе 0, 1, 2, 5, 14 и 15. Красным цветом выделены непустые поддеревья]] | [[Файл:Дерево_ван_Эмде_Боаса.png|right|570px|thumb|4-дерево, содержащее в себе 0, 1, 2, 5, 14 и 15. Красным цветом выделены непустые поддеревья]] | ||
Строка 25: | Строка 25: | ||
Во вспомогательном дереве <tex>aux</tex> будем хранить все такие числа <tex>p</tex>, что дерево <tex>children[p]</tex> не пусто. | Во вспомогательном дереве <tex>aux</tex> будем хранить все такие числа <tex>p</tex>, что дерево <tex>children[p]</tex> не пусто. | ||
− | = Операции = | + | == Операции == |
− | == empty == | + | === empty === |
Чтобы определить, пусто ли дерево, будем изначально инициализировать поле <tex>min</tex> числом, которое не лежит в интервале <tex>[0;2^k)</tex>. Назовем это число <tex>none</tex>. Например, это может быть <tex>-1</tex>, если мы храним в числа в знаковом целочисленном типе, или <tex>2^k</tex>, если в беззнаковом. Тогда проверка на пустоту дерева будет заключаться лишь в сравнении поля <tex>min</tex> с этим числом. | Чтобы определить, пусто ли дерево, будем изначально инициализировать поле <tex>min</tex> числом, которое не лежит в интервале <tex>[0;2^k)</tex>. Назовем это число <tex>none</tex>. Например, это может быть <tex>-1</tex>, если мы храним в числа в знаковом целочисленном типе, или <tex>2^k</tex>, если в беззнаковом. Тогда проверка на пустоту дерева будет заключаться лишь в сравнении поля <tex>min</tex> с этим числом. | ||
<pre> | <pre> | ||
Строка 36: | Строка 36: | ||
</pre> | </pre> | ||
− | == min и max == | + | === min и max === |
Так как мы храним в дереве минимальное и максимальное значения, то данные операции не требуют ничего, кроме вывода значения поля <tex>min</tex> или <tex>max</tex> в соответствии с запросом. Время выполнения данных операций соответственно <tex>O(1)</tex>. | Так как мы храним в дереве минимальное и максимальное значения, то данные операции не требуют ничего, кроме вывода значения поля <tex>min</tex> или <tex>max</tex> в соответствии с запросом. Время выполнения данных операций соответственно <tex>O(1)</tex>. | ||
− | == find == | + | |
+ | === find === | ||
Алгоритм поиска сам напрашивается из выше описанной структуры: | Алгоритм поиска сам напрашивается из выше описанной структуры: | ||
*если дерево пусто, то число не содержится в нашей структуре. | *если дерево пусто, то число не содержится в нашей структуре. | ||
Строка 55: | Строка 56: | ||
Заметим, что выполняя операцию <tex>find</tex>, мы либо спускаемся по дереву на один уровень ниже, либо, если нашли нужный нам элемент, выходим из нее. В худшем случае мы спустимся от корня до какого-нибудь 1-дерева, то есть выполним операцию <tex>find</tex> столько раз, какова высота нашего дерева. На каждом уровне мы совершаем <tex>O(1)</tex> операций. Следовательно время работы <tex>O(\log k)</tex>. | Заметим, что выполняя операцию <tex>find</tex>, мы либо спускаемся по дереву на один уровень ниже, либо, если нашли нужный нам элемент, выходим из нее. В худшем случае мы спустимся от корня до какого-нибудь 1-дерева, то есть выполним операцию <tex>find</tex> столько раз, какова высота нашего дерева. На каждом уровне мы совершаем <tex>O(1)</tex> операций. Следовательно время работы <tex>O(\log k)</tex>. | ||
− | == insert == | + | === insert === |
Операция вставки элемента <tex>x</tex> состоит из нескольких частей: | Операция вставки элемента <tex>x</tex> состоит из нескольких частей: | ||
Строка 88: | Строка 89: | ||
Нетрудно увидеть, что данная операция работает за время <tex>O(\log k)</tex>. На каждом уровне дерева мы выполняем <tex>O(1)</tex> операций. После этого возможны 2 случая: поддерево <tex>children[high(x)]</tex> пусто, и мы будем производить дальнейшую вставку и в него, и во вспомогательное дерево <tex>aux</tex>, или же поддерево не пусто, и мы просто спустимся на уровень ниже. Но если поддерево <tex>children[high(x)]</tex> пусто, то вставка в него будет выполнена за <tex>O(1)</tex>, так как мы всего лишь обновим поля <tex>min</tex> и <tex>max</tex>. Все остальные операции будут выполнятся уже со вспомогательным деревом <tex>aux</tex>, высота которого на 1 уровень меньше, чем высота текущего. Если же поддерево <tex>children[high(x)]</tex> не пусто, то мы просто перейдем к вставке элемента в это поддерево, высота которого так же на 1 меньше, чем у текущего. В итоге, каждый раз, выполнив <tex>O(1)</tex> операций, мы переходим к дереву, высота которого на 1 меньше, чем у текущего. Следовательно, количество операций пропорционально высоте дерева, которая, как уже было показано, <tex>O(\log k)</tex>. То есть операция вставки займет <tex>O(\log k)</tex> времени. | Нетрудно увидеть, что данная операция работает за время <tex>O(\log k)</tex>. На каждом уровне дерева мы выполняем <tex>O(1)</tex> операций. После этого возможны 2 случая: поддерево <tex>children[high(x)]</tex> пусто, и мы будем производить дальнейшую вставку и в него, и во вспомогательное дерево <tex>aux</tex>, или же поддерево не пусто, и мы просто спустимся на уровень ниже. Но если поддерево <tex>children[high(x)]</tex> пусто, то вставка в него будет выполнена за <tex>O(1)</tex>, так как мы всего лишь обновим поля <tex>min</tex> и <tex>max</tex>. Все остальные операции будут выполнятся уже со вспомогательным деревом <tex>aux</tex>, высота которого на 1 уровень меньше, чем высота текущего. Если же поддерево <tex>children[high(x)]</tex> не пусто, то мы просто перейдем к вставке элемента в это поддерево, высота которого так же на 1 меньше, чем у текущего. В итоге, каждый раз, выполнив <tex>O(1)</tex> операций, мы переходим к дереву, высота которого на 1 меньше, чем у текущего. Следовательно, количество операций пропорционально высоте дерева, которая, как уже было показано, <tex>O(\log k)</tex>. То есть операция вставки займет <tex>O(\log k)</tex> времени. | ||
− | == remove == | + | === remove === |
Удаление из дерева также делится на несколько подзадач: | Удаление из дерева также делится на несколько подзадач: | ||
*если <tex> min </tex> = <tex> max </tex> = <tex> x </tex>, значит в дереве один элемент, удалим его и отметим, что дерево пусто. | *если <tex> min </tex> = <tex> max </tex> = <tex> x </tex>, значит в дереве один элемент, удалим его и отметим, что дерево пусто. | ||
Строка 122: | Строка 123: | ||
Оценка времени работы операции <tex>remove</tex> такая же, как и у операции <tex>insert</tex>. На каждом уровне дерева мы совершаем <tex>O(1)</tex> операций и переходим к удалению элементов максимум в двух деревьях(в одном поддереве и во вспомогательном дереве), чьи высоты на один меньше текущей. Но если мы производим операцию удаления из вспомогательного дерева, значит удаление из поддерева потребовало <tex>O(1)</tex> операций, так как оно содержало всего один элемент. В итоге, количество операций пропорционально высоте дерева, то есть <tex>O(\log k)</tex>. | Оценка времени работы операции <tex>remove</tex> такая же, как и у операции <tex>insert</tex>. На каждом уровне дерева мы совершаем <tex>O(1)</tex> операций и переходим к удалению элементов максимум в двух деревьях(в одном поддереве и во вспомогательном дереве), чьи высоты на один меньше текущей. Но если мы производим операцию удаления из вспомогательного дерева, значит удаление из поддерева потребовало <tex>O(1)</tex> операций, так как оно содержало всего один элемент. В итоге, количество операций пропорционально высоте дерева, то есть <tex>O(\log k)</tex>. | ||
− | == next и prev == | + | === next и prev === |
Алгоритм нахождения следующего элемента, как и два предыдущих, сводится к рассмотрению случая, когда дерево содержит не более одного элемента, либо к поиску в одном из его поддеревьев: | Алгоритм нахождения следующего элемента, как и два предыдущих, сводится к рассмотрению случая, когда дерево содержит не более одного элемента, либо к поиску в одном из его поддеревьев: | ||
*если дерево пусто, или максимум этого дерева не превосходит <tex> x </tex>, то следующего элемента в этом дереве не существует. | *если дерево пусто, или максимум этого дерева не превосходит <tex> x </tex>, то следующего элемента в этом дереве не существует. | ||
Строка 154: | Строка 155: | ||
Время работы, как и всех предыдущих функций, оценивается так же, и равно <tex>O(\log k)</tex>. Функция <tex> prev </tex> реализуется аналогично. | Время работы, как и всех предыдущих функций, оценивается так же, и равно <tex>O(\log k)</tex>. Функция <tex> prev </tex> реализуется аналогично. | ||
− | = Преимущества и недостатки = | + | == Преимущества и недостатки == |
− | == Преимущества == | + | === Преимущества === |
Главным преимуществом данной структуры является ее быстродействие. Асимптотически время работы операций дерева ван Эмде Боаса лучше, чем, например, у [[АВЛ-дерево|АВЛ]], [[Красно-черное дерево|красно-черных]], [[2-3 дерево|2-3]], [[Splay-дерево|splay]] и [[Декартово дерево|декартовых]] деревьев уже при небольшом количестве элементов. Конечно, из-за довольно непростой реализации возникают немалые постоянные множители, которые снижают практическую эффективность данной структуры. Но все же, при большом количестве элементов, эффективность дерева ван Эмде Боаса проявляется и на практике, что позволяет нам использовать данную структуру не только как эффективное дерево поиска, но и в других задачах. Например: | Главным преимуществом данной структуры является ее быстродействие. Асимптотически время работы операций дерева ван Эмде Боаса лучше, чем, например, у [[АВЛ-дерево|АВЛ]], [[Красно-черное дерево|красно-черных]], [[2-3 дерево|2-3]], [[Splay-дерево|splay]] и [[Декартово дерево|декартовых]] деревьев уже при небольшом количестве элементов. Конечно, из-за довольно непростой реализации возникают немалые постоянные множители, которые снижают практическую эффективность данной структуры. Но все же, при большом количестве элементов, эффективность дерева ван Эмде Боаса проявляется и на практике, что позволяет нам использовать данную структуру не только как эффективное дерево поиска, но и в других задачах. Например: | ||
*cортировка последовательности из <tex> n </tex> чисел. Вставим элементы в дерево, найдем минимум и <tex> n - 1</tex> раз вызовем функцию <tex> next </tex>. Так как все операции занимают не более <tex> O(\log k)</tex> времени, то итоговая асимптотика алгоритма <tex> O(n \cdot \log k)</tex>, что даже лучше, чем [[Цифровая сортировка|цифровая сортировка]], асимптотика которой <tex> O(n \cdot k)</tex>. | *cортировка последовательности из <tex> n </tex> чисел. Вставим элементы в дерево, найдем минимум и <tex> n - 1</tex> раз вызовем функцию <tex> next </tex>. Так как все операции занимают не более <tex> O(\log k)</tex> времени, то итоговая асимптотика алгоритма <tex> O(n \cdot \log k)</tex>, что даже лучше, чем [[Цифровая сортировка|цифровая сортировка]], асимптотика которой <tex> O(n \cdot k)</tex>. | ||
*[[Алгоритм Дейкстры|алгоритм Дейкстры]]. Данный алгоритм с использованием [[Двоичная куча|двоичной кучи]] для поиска минимума работает за <tex> O(E \cdot \log V)</tex>, где <tex> V </tex> {{---}} количество вершин в графе, а <tex> E </tex> {{---}} количество ребер между ними. Если же вместо кучи использовать дерево ван Эмде Боаса, то релаксация и поиск минимума будут занимать уже не <tex> \log V </tex>, а <tex> \log k </tex>, и итоговая асимптотика этого алгоритма снизится до <tex> O(E \cdot \log k)</tex>. | *[[Алгоритм Дейкстры|алгоритм Дейкстры]]. Данный алгоритм с использованием [[Двоичная куча|двоичной кучи]] для поиска минимума работает за <tex> O(E \cdot \log V)</tex>, где <tex> V </tex> {{---}} количество вершин в графе, а <tex> E </tex> {{---}} количество ребер между ними. Если же вместо кучи использовать дерево ван Эмде Боаса, то релаксация и поиск минимума будут занимать уже не <tex> \log V </tex>, а <tex> \log k </tex>, и итоговая асимптотика этого алгоритма снизится до <tex> O(E \cdot \log k)</tex>. | ||
− | == Недостатки == | + | === Недостатки === |
*существенным недостатком данной структуры является то, что она позволяет хранить лишь целые неотрицательные числа, что существенно снижает область ее применения, по сравнению с другими деревьями поиска, которые не используют внутреннюю структуру элементов, хранящихся в них. | *существенным недостатком данной структуры является то, что она позволяет хранить лишь целые неотрицательные числа, что существенно снижает область ее применения, по сравнению с другими деревьями поиска, которые не используют внутреннюю структуру элементов, хранящихся в них. | ||
*другим серьезным недостатком является количество занимаемой памяти. Дерево, хранящее <tex> k </tex>-битные числа, занимает <tex> O(2^k) </tex> памяти, что несложно доказывается индукцией, учитывая, что <tex> S(2^k)=(2^{k/2} + 1) \cdot S(2^{k/2}) + O(2^{k/2})</tex>, где <tex> S(2^i) </tex> {{---}} количество памяти, занимаемое деревом, в котором хранятся <tex> i </tex>-битные числа. Впрочем, можно попытаться частично избежать огромного расхода памяти, создавая необходимые поддеревья «лениво», то есть только тогда, когда они нам потребуются. | *другим серьезным недостатком является количество занимаемой памяти. Дерево, хранящее <tex> k </tex>-битные числа, занимает <tex> O(2^k) </tex> памяти, что несложно доказывается индукцией, учитывая, что <tex> S(2^k)=(2^{k/2} + 1) \cdot S(2^{k/2}) + O(2^{k/2})</tex>, где <tex> S(2^i) </tex> {{---}} количество памяти, занимаемое деревом, в котором хранятся <tex> i </tex>-битные числа. Впрочем, можно попытаться частично избежать огромного расхода памяти, создавая необходимые поддеревья «лениво», то есть только тогда, когда они нам потребуются. | ||
− | = Источники = | + | == Источники == |
*[http://en.wikipedia.org/wiki/Van_Emde_Boas_tree Van Emde Boas tree — Wikipedia] | *[http://en.wikipedia.org/wiki/Van_Emde_Boas_tree Van Emde Boas tree — Wikipedia] |
Версия 13:18, 14 апреля 2012
Определение: |
Дерево ван Эмде Боаса — структура данных, представляющая собой дерево поиска, позволяющее хранить целые неотрицательные числа в интервале | и осуществлять над ними все соответствующие дереву поиска операции.
Проще говоря, данная структура позволяет хранить
-битные числа и производить над ними операции , , , , , , и некоторые другие операции, которые присущи всем деревьям поиска.Особенностью этой структуры является то, что все операции выполняются за
, что асимптотически лучше, чем в большинстве других деревьев поиска, где — количество элементов в дереве.Содержание
Структура
Для удобства работы с деревом будем использовать
, равные степени двойки.Как уже было сказано выше,
-дерево хранит числа в интервале . Тогда 1-дерево хранит информацию, содержатся ли в нем 0 и 1.Построим
-дерево, при . В нем будут хранится:- массив , состоящий из -деревьев
- вспомогательное -дерево, которое назовем
- максимальный и минимальный элемент, хранящийся в этом дереве (если оно не является пустым), причем дополнительно в самом дереве эти элементы хранить не будем.
Пусть у нас есть
-битное число . Разобьем это число таким образом, что — число, соответствующее старшим битам числа , а соответствует младшим битам. Тогда информация, хранится ли в данном дереве число , эквивалентна информации, содержится ли в дереве число .Нетрудно увидеть, что высота подобного дерева
, так как каждый следующий уровень дерева содержит числа, количество битов в которых в 2 раза меньше, чем в предыдущем.Во вспомогательном дереве
будем хранить все такие числа , что дерево не пусто.Операции
empty
Чтобы определить, пусто ли дерево, будем изначально инициализировать поле
числом, которое не лежит в интервале . Назовем это число . Например, это может быть , если мы храним в числа в знаковом целочисленном типе, или , если в беззнаковом. Тогда проверка на пустоту дерева будет заключаться лишь в сравнении поля с этим числом.empty(T) if T.min == none return true; else return false;
min и max
Так как мы храним в дереве минимальное и максимальное значения, то данные операции не требуют ничего, кроме вывода значения поля
или в соответствии с запросом. Время выполнения данных операций соответственно .find
Алгоритм поиска сам напрашивается из выше описанной структуры:
- если дерево пусто, то число не содержится в нашей структуре.
- если число равно полю или , то число в дереве есть.
- иначе ищем число в поддереве .
find(T, x) if empty(T) return false; if T.min == x or T.max == x return true; return find(T.children[high(x)], low(x));
Заметим, что выполняя операцию
, мы либо спускаемся по дереву на один уровень ниже, либо, если нашли нужный нам элемент, выходим из нее. В худшем случае мы спустимся от корня до какого-нибудь 1-дерева, то есть выполним операцию столько раз, какова высота нашего дерева. На каждом уровне мы совершаем операций. Следовательно время работы .insert
Операция вставки элемента
состоит из нескольких частей:- если дерево пусто или в нем содержится единственный элемент ( = ), то присвоим полям и соответствующие значения. Делать что-то еще бессмысленно, так как информация записанная в и полностью описывает состояние текущего дерева и удовлетворяет структуре нашего дерева.
- иначе:
- если элемент больше или меньше текущего дерева, то обновим соответствующее значение минимума или максимума, а старый минимум или максимум добавим в дерево.
- вставим во вспомогательное дерево число , если соответствующее поддерево до этого было пусто.
- вставим число в поддерево , за исключением ситуации, когда текущее дерево — это 1-дерево, и дальнейшая вставка не требуется.
insert(T, x) if empty(T) // проверка на пустоту текущего дерева T.min = x; T.max = x; else if T.min == T.max // проверка, что в дереве один элемент if T.min < x T.max = x; else T.min = x; else if T.min > x swap(T.min, x); // релаксация минимума if T.max < x swap(T.max, x); // релаксация максимума if T.k != 1 if empty(T.children[high(x)]) insert(T.aux, high(x)); // вставка high(x) во вспомогательно дерево aux insert(T.children[high(x)], low(x)); // вставка low(x) в поддерево children[high(x)]
Нетрудно увидеть, что данная операция работает за время
. На каждом уровне дерева мы выполняем операций. После этого возможны 2 случая: поддерево пусто, и мы будем производить дальнейшую вставку и в него, и во вспомогательное дерево , или же поддерево не пусто, и мы просто спустимся на уровень ниже. Но если поддерево пусто, то вставка в него будет выполнена за , так как мы всего лишь обновим поля и . Все остальные операции будут выполнятся уже со вспомогательным деревом , высота которого на 1 уровень меньше, чем высота текущего. Если же поддерево не пусто, то мы просто перейдем к вставке элемента в это поддерево, высота которого так же на 1 меньше, чем у текущего. В итоге, каждый раз, выполнив операций, мы переходим к дереву, высота которого на 1 меньше, чем у текущего. Следовательно, количество операций пропорционально высоте дерева, которая, как уже было показано, . То есть операция вставки займет времени.remove
Удаление из дерева также делится на несколько подзадач:
- если = = , значит в дереве один элемент, удалим его и отметим, что дерево пусто.
- если , то мы должны найти следующий минимальный элемент в этом дереве, присвоить значение второго минимального элемента и удалить его из того места, где он хранится. Второй минимум — это либо , либо (для случая действуем аналогично).
- если же и , то мы должны удалить из поддерева .
Нельзя забывать, что если мы удаляем последнее вхождение
, то мы должны удалить из вспомогательного дерева.remove(T, x) if T.min == x and T.max == x // случай, когда в дереве один элемент T.min = none; return; if T.min == x if empty(T.aux) T.min = T.max; return; x = T.children[T.aux.min].min; T.min = x; if T.max == x if empty(T.aux) T.max = T.min; return; else x = T.children[T.aux.max].max; T.max = x; if empty(T.aux) // случай, когда элемента x нет в дереве return; remove(T.children[high(x)], low(x)); if empty(T.children[high(x)]) // если мы удалили из поддерева последний элемент remove(T.aux, high(x)); // то удаляем информацию, что это поддерево не пусто
Оценка времени работы операции
такая же, как и у операции . На каждом уровне дерева мы совершаем операций и переходим к удалению элементов максимум в двух деревьях(в одном поддереве и во вспомогательном дереве), чьи высоты на один меньше текущей. Но если мы производим операцию удаления из вспомогательного дерева, значит удаление из поддерева потребовало операций, так как оно содержало всего один элемент. В итоге, количество операций пропорционально высоте дерева, то есть .next и prev
Алгоритм нахождения следующего элемента, как и два предыдущих, сводится к рассмотрению случая, когда дерево содержит не более одного элемента, либо к поиску в одном из его поддеревьев:
- если дерево пусто, или максимум этого дерева не превосходит , то следующего элемента в этом дереве не существует.
- если меньше поля , то искомый элемент и есть .
- если дерево содержит не более двух элементов, и , то искомый элемент .
- если же в дереве более двух элементов, то:
- если в дереве есть еще числа, большие , и чьи старшие биты равны , то продолжим поиск в поддереве , где будем искать число, следующее после .
- иначе искомым элементом является либо минимум следующего непустого поддерева, если такое есть, либо максимум текущего дерева в противном случае.
Так как в поддеревьях хранятся не все биты исходных элементов, а только часть их, то для восстановления исходного числа, по имеющимся старшим и младшим битам, будем использовать функцию
.next(T, x) if empty(T) or T.max <= x return none; // следующего элемента нет if T.min > x return T.min; if empty(T.aux) return T.max; // в дереве не более двух элементов else if not empty(T.children[high(x)]) and T.childen[high(x)].max > low(x) return merge(high(x), next(T.children[high(x)])); // случай, когда следующее число начинается с high(x) else // иначе найдем следующее непустое поддерево nextHigh = next(T.aux, high(x)); if nextHigh == null return T.max; // если такого нет, вернем максимум else return merge(high(x), T.children[nextHigh].min); // если есть, вернем минимум найденного поддерева
Время работы, как и всех предыдущих функций, оценивается так же, и равно
. Функция реализуется аналогично.Преимущества и недостатки
Преимущества
Главным преимуществом данной структуры является ее быстродействие. Асимптотически время работы операций дерева ван Эмде Боаса лучше, чем, например, у АВЛ, красно-черных, 2-3, splay и декартовых деревьев уже при небольшом количестве элементов. Конечно, из-за довольно непростой реализации возникают немалые постоянные множители, которые снижают практическую эффективность данной структуры. Но все же, при большом количестве элементов, эффективность дерева ван Эмде Боаса проявляется и на практике, что позволяет нам использовать данную структуру не только как эффективное дерево поиска, но и в других задачах. Например:
- cортировка последовательности из цифровая сортировка, асимптотика которой . чисел. Вставим элементы в дерево, найдем минимум и раз вызовем функцию . Так как все операции занимают не более времени, то итоговая асимптотика алгоритма , что даже лучше, чем
- алгоритм Дейкстры. Данный алгоритм с использованием двоичной кучи для поиска минимума работает за , где — количество вершин в графе, а — количество ребер между ними. Если же вместо кучи использовать дерево ван Эмде Боаса, то релаксация и поиск минимума будут занимать уже не , а , и итоговая асимптотика этого алгоритма снизится до .
Недостатки
- существенным недостатком данной структуры является то, что она позволяет хранить лишь целые неотрицательные числа, что существенно снижает область ее применения, по сравнению с другими деревьями поиска, которые не используют внутреннюю структуру элементов, хранящихся в них.
- другим серьезным недостатком является количество занимаемой памяти. Дерево, хранящее -битные числа, занимает памяти, что несложно доказывается индукцией, учитывая, что , где — количество памяти, занимаемое деревом, в котором хранятся -битные числа. Впрочем, можно попытаться частично избежать огромного расхода памяти, создавая необходимые поддеревья «лениво», то есть только тогда, когда они нам потребуются.