Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат? |
Сбалансированные деревья
Характеристики производительности
Как для конкретного приложения осуществить выбор между рандомизированными BST-деревьями, скошенными BST-деревьями, RB-деревьями бинарного поиска и слоеными списками? До сих пор наше внимание было сосредоточено на различной природе гарантирования производительности, которую обеспечивают эти алгоритмы. Главными определяющими факторами всегда являются время и память, но необходимо учитывать и ряд других аспектов. В этом разделе мы кратко рассмотрим вопросы реализации, эмпирические исследования, оценки времени выполнения и требования к памяти.
Все алгоритмы на основе деревьев используют ротации; реализация ротаций на пути поиска — важная составная часть большинства алгоритмов для сбалансированных деревьев. Мы использовали рекурсивные реализации, в которых ссылки на узлы на пути поиска неявно сохраняются в локальных переменных в стеке рекурсии. Но каждый из этих алгоритмов может быть реализован и нерекурсивно, работая с постоянным количеством узлов и выполняя постоянное количество операций над ссылками в перерасчете на один узел во время нисходящего прохода по дереву.
Из трех основанных на деревьях алгоритмов проще всего реализовать рандомизированные BST-деревья. Здесь главные требования — надежность генератора случайных чисел и не слишком большие затраты времени на генерацию случайных битов. Скошенные деревья несколько более сложны, но являются очевидным обобщением стандартного алгоритма вставки в корень. RB-деревья бинарного поиска требуют еще немного большего кодирования, поскольку в них нужно проверять и изменять биты цвета. Одно из преимуществ RB-деревьев по сравнению с двумя другими алгоритмами — возможность использования битов цвета для проверки логики при отладке и для обеспечения быстрого поиска в любой момент времени на протяжении жизни дерева. Рассматривая скошенное BST-дерево, невозможно выяснить, все ли необходимые преобразования выполнил создавший его код; программная ошибка может приводить (только!) к проблемам, связанным с производительностью. Аналогично, ошибка в генераторе случайных чисел, используемом для рандомизированных BST-деревьев или слоеных списков, может привести к не замеченным в противном случае проблемам производительности.
Слоеные списки легко реализовать, и они особенно привлекательны, если требуется поддерживать полный набор операций для таблиц символов, поскольку для них можно легко сформулировать и естественно реализовать все операции — найти, вставить, удалить, объединить, выбрать и сортировать. Внутренний цикл для выполнения поиска в слоеных списках длиннее, чем в деревьях (для него требуется дополнительный индекс в массиве ссылок или дополнительный рекурсивный вызов для спуска на уровень ниже), поэтому время поиска и вставки несколько увеличено. Кроме того, слоеные списки ставят программиста в зависимость от генератора случайных чисел, поскольку отладка программы, поведение которой носит случайный характер — весьма сложная задача, и некоторые программисты очень не любят работать с узлами, содержащими случайное количество ссылок.
В таблица 13.1 приведены экспериментальные данные по производительности четырех рассмотренных в этой главе методов, а также элементарных реализаций BST-деревьев, описанных в "Таблицы символов и деревья бинарного поиска" , для 32-разрядных целых ключей. Приведенные в этой таблице данные подтверждают аналитические результаты, полученные в разделах 13.2, 13.4 и 13.5. RB-деревья работают со случайными ключами гораздо быстрее, чем другие алгоритмы. Пути в них на 35% короче, чем в рандомизированных или скошенных BST-деревьях, а в их внутренних циклах выполняется меньше действий. Рандомизированные деревья и слоеные списки требуют генерации по меньшей мере одного случайного числа для каждой вставки, а скошенные BST-деревья выполняют ротацию в каждом узле для каждой вставки и каждого поиска. Дополнительные затраты при использовании RB-деревьев бинарного поиска заключаются в проверке значений двух битов в каждом узле во время вставки, а иногда приходится выполнять и ротацию. При неравномерном доступе скошенные BST-деревья могут обеспечить более короткие пути, но эта экономия, скорее всего, будет перекрыта тем, что и для поиска, и для вставки потребуются ротации в каждом узле во внутреннем цикле, за исключением, быть может, крайних случаев.
N | Построение | Неудачные поиски | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
B | T | R | S | C | L | B | T | R | S | C | L | |
1250 | 0 | 1 | 3 | 2 | 1 | 2 | 1 | 1 | 0 | 0 | 0 | 2 |
2500 | 2 | 4 | 6 | 3 | 1 | 4 | 1 | 1 | 1 | 2 | 1 | 3 |
5000 | 4 | 7 | 14 | 8 | 5 | 10 | 3 | 3 | 3 | 3 | 2 | 7 |
12500 | 11 | 23 | 43 | 24 | 16 | 28 | 10 | 9 | 9 | 9 | 7 | 18 |
25000 | 27 | 51 | 101 | 50 | 32 | 57 | 19 | 19 | 26 | 21 | 16 | 43 |
50000 | 63 | 114 | 220 | 117 | 74 | 133 | 48 | 49 | 60 | 46 | 36 | 98 |
100000 | 159 | 277 | 447 | 282 | 177 | 310 | 118 | 106 | 132 | 112 | 84 | 229 |
200000 | 347 | 621 | 996 | 636 | 411 | 670 | 235 | 234 | 294 | 247 | 193 | 523 |
Обозначения: | |
B | Стандартное BST-дерево (программа 12.8) |
T | BST-дерево, построенное вставками в корень (программа 12.13) |
R | Рандомизированное BST-дерево (программа 13.2) |
S | Скошенное BST-дерево (упражнение 13.33 и программа 13.5) |
C | RB-дерево бинарного поиска (программа 13.6) |
L | Слоеный список (программы 13.7 и 13.9) |
Эти сравнительные значения времени построения и поиска в BST-деревьях, образованных из случайных последовательностей N 32-разрядных чисел, при различных значениях N, показывают, что все методы обеспечивают хорошую производительность даже для очень больших таблиц, но RB-деревья работают значительно быстрее других методов. Во всех методах используется стандартный поиск в BST-дереве, за исключением скошенных BST-деревьев, где при поиске выполняется скос для перемещения часто посещаемых узлов ближе к вершине, и слоеных списков, в которых используется, по сути дела, этот же алгоритм, но по отношению к другой структуре данных.
Скошенные BST-деревья не требуют использования дополнительной памяти под информацию о балансе; RB-деревья бинарного поиска требуют 1 дополнительный бит, а рандомизированные BST-деревья требуют наличия поля счетчика. Во многих приложениях поле счетчика используется и для других целей, поэтому для рандомизированных BST-деревьев оно может и не вызывать дополнительных затрат. На самом деле добавление этого поля может потребоваться и при использовании скошенных BST-деревьев, RB-деревьев бинарного поиска или слоеных списков. При необходимости RB-деревья бинарного поиска можно сделать столь же эффективными по памяти, как и скошенные BST-деревья, исключив бит цвета (см. упражнение 13.65). В современных приложениях объем памяти не столь важен, как когда-то, однако аккуратный программист всегда избегает напрасных затрат. Например, необходимо помнить, что некоторые системы для небольшого поля счетчика или 1-разрядного поля цвета в узле могут использовать целое 32-разрядное слово, а некоторые другие системы могут упаковывать поля в памяти так, что их распаковка требует значительного дополнительного времени. Если объем памяти ограничен, слоеные списки с большим параметром t могут уменьшить объем памяти, требуемый для ссылок, почти в два раза — ценой более медленного (но все же логарифмического) поиска. Некоторые приемы позволяют реализовать основанные на деревьях методы с использованием лишь одной ссылки на узел (см. упражнение 12.68).
Подводя итоги, можно сказать, что все рассмотренные в этой главе методы обеспечивают высокую производительность типичных приложений, при этом каждый метод обладает собственными достоинствами для тех, кто заинтересован в разработке высокопроизводительных реализаций таблиц символов. Скошенные BST-деревья обеспечивают высокую производительность как метод самоорганизующегося поиска, особенно когда типичны частые обращения к небольшому набору ключей. Рандомизированные BST-деревья обычно работают быстрее, и с их помощью легче реализовать полнофункциональные таблицы символов. Слоеные списки просты для понимания и могут обеспечить логарифмическую зависимость времени поиска при меньших по сравнению с другими методами затратах памяти. А RB-деревья бинарного поиска привлекательны для библиотечных реализаций таблицы символов, поскольку они обеспечивают гарантированные границы производительности в худшем случае и наиболее быстрые алгоритмы поиска и вставки случайных данных.
Кроме специфичных использований в приложениях, это множество решений задачи разработки эффективных реализаций АТД таблицы символов важно также и потому, что оно иллюстрирует фундаментальные подходы к разработке алгоритмов, которые можно использовать и для решения других задач. При постоянной потребности в простых оптимальных алгоритмах мы часто сталкиваемся с почти оптимальными алгоритмами, подобными рассмотренным в этой главе. Вообще-то, как можно было заметить на примере сортировки, алгоритмы, основанные на сравнениях — начало, но далеко не конец. Переходя к абстракциям более низкого уровня, в которых возможна обработка фрагментов ключей, можно разрабатывать реализации, которые работают даже быстрее, чем рассмотренные в этой главе, что и будет продемонстрировано в "Хеширование" и "Поразрядный поиск" .
Упражнения
13.85. Разработайте реализацию таблицы символов, использующую рандомизированные BST-деревья, которая содержит деструктор, конструктор копирования и перегруженную операцию присваивания и поддерживает операции создать, подсчитать, найти, вставить, удалить, объединить, выбрать и сортировать для АТД таблицы символов первого класса с поддержкой клиентских дескрипторов элементов (см. упражнения 12.6 и 12.7).
13.86. Разработайте реализацию таблицы символов, использующую слоеные списки, которая содержит деструктор, конструктор копирования и перегруженную операцию присваивания и поддерживает операции создать, подсчитать, найти, вставить, удалить, объединить, выбрать и сортировать для АТД таблицы символов первого класса с поддержкой клиентских дескрипторов элементов (см. упражнения 12.6 и 12.7).