Глава 1. Введение в разработку алгоритмов 51
4. [5] Начертите сеть дорог с двумя точками а и b, самый короткий маршрут между кото-
рыми не является маршрутом с наименьшим количеством поворотов.
5. [4] Задача о рюкзаке: имея множество целых чисел S = {s1, s2, ..., sn} и целевое число Т,
найти такое подмножество множества S, сумма которого в точности равна Т. Например,
множество S = {l, 2, 5, 9, 10} содержит такое подмножество, сумма элементов которого
равна T = 22, но не T = 23.
Найти контрпримеры для каждого из следующих алгоритмов решения задачи
о рюкзаке, т. е. найти такое множество S и число Т, при которых алгоритм не находит
решения, полностью заполняющего рюкзак, хотя такое решение и существует:
• вкладывать элементы множества S в рюкзак в порядке слева направо, если они под-
ходят (т. е. алгоритм «первый подходящий»);
• вкладывать элементы множества S в рюкзак в порядке от наименьшего до наиболь-
шего (т. е. используя алгоритм «первый лучший»);
• вкладывать элементы множества S в рюкзак в порядке от наибольшего до наимень-
шего.
6. [5] Задача о покрытии множества: имея множество S семейства подмножеств S1, ..., Sm
универсального множества U = {l, ..., n}, найдите семейство подмножеств T ⊆ S наи-
меньшей мощности, чтобы ∪ti ∈T ti = U . Например, для семейства подмножеств S1 =
= {l, 3, 5}, S2 = {2, 4}, S3 = {l, 4} и S4 = {2, 5} покрытием множества {1, ..., 5} будет
семейство подмножеств S1 и S2. Приведите контрпример для следующего алгоритма: вы-
бираем самое мощное подмножество для покрытия, после чего удаляем все его элементы
из универсального множества. Повторяем добавление подмножества, содержащего наи-
большее количество неохваченных элементов, пока все элементы не будут покрыты.
7. [5] Задача максимальной клики графа G = (V, E) требует найти такое наибольшее под-
множество C вершин V, в котором между каждой парой вершин в С есть ребро в Е. Соз-
дайте контрпример для следующего алгоритма: сортируем вершины графа G по степени
в нисходящем порядке. Рассматриваем все вершины в порядке степени, добавляя верши-
ну в клику, если она является соседом всех вершин — членов клики в текущий момент.
Повторяем процесс до тех пор, пока не будут рассмотрены все вершины.
Доказательство правильности
8. [3] Докажите правильность следующего рекурсивного алгоритма умножения двух нату-
ральных чисел для всех целочисленных констант c ≥ 2:
Multiply(y, z)
if z = 0 then return(0) else
return(Multiply(cy,[z/c]) + y·(z mod c))
9. [3] Докажите правильность следующего алгоритма вычисления полинома P(x) = anxn +
+ an–1xn–1 + ... + a1x + a0:
Horner(A, x)
p = an
for i from n-1 to 0
p = p · x + ai
return p
52 Часть I. Практическая разработка алгоритмов
10. [3] Докажите правильность следующего алгоритма сортировки:
Bubblesort (A)
var int i,j
for i from n to 1
for j from 1 to i – 1
if (A[j]>A[j+1]
меняем местами значения A[j] и A[j + 1]
11. [5] Наибольшим общим делителем (нод) положительных целых чисел x и y является
наибольшее такое целое число d, на которое делится как число x, так и число y. Евкли-
дов алгоритм для вычисления нод(x, y), где x > y, сводит исходную задачу к более про-
стой:
нод(x, y) = нод (y, x mod y)
Докажите правильность евклидова алгоритма.
Математическая индукция
Для доказательства пользуйтесь методом математической индукции.
∑12. [3] Докажите, что in=1i = n(n +1) / 2 для n ≥ 0.
∑13. [3] Докажите, что n i2 = n(n +1)(2n +1) / 6 для n ≥ 0.
i =1
∑14. [3] Докажите, что in=1i3 = n2 (n +1)2 / 4 для n ≥ 0.
n
15. [3] Докажите, что ∑ i(i +1)(i + 2) = n(n +1)(n + 2)(n + 3) / 4 .
i =1
∑16. [5] Докажите, что n ai = an+1 −1 для n ≥ 1, a ≠ 1.
i=0 a −1
∑n 1 = n для n ≥1.
17. [3] Докажите, что
i=1 i(i +1) n +1
18. [3] Докажите, что n3 + 2n делится на 3 для всех n ≥ 0.
19. [3] Докажите, что дерево с n вершинами имеет в точности n – 1 ребер.
20. [3] Докажите, что сумма кубов первых n положительных целых чисел равна квадрату
суммы этих целых чисел, т. е.
nn
∑i3 = (∑i)2 .
i=1 i =1
Приблизительные подсчеты
21. [3] Содержат ли все ваши книги, по крайней мере, миллион страниц? Каково общее ко-
личество страниц всех книг в вашей институтской библиотеке?
22. [3] Сколько слов содержит эта книга?
Глава 1. Введение в разработку алгоритмов 53
23. [3] Сколько часов составляет один миллион секунд? А сколько дней? Выполните все
необходимые вычисления в уме.
24. [3] Сколько городов и поселков в Соединенных Штатах?
25. [3] Сколько кубических километров воды изливается из устья Миссисипи каждый день?
Не пользуйтесь никакой справочной информацией. Опишите все предположения, сде-
ланные вами для получения ответа.
26. [3] Сколько точек Starbucks или McDonald’s в вашей стране?
27. [3] Сколько времени потребовалось бы, чтобы опорожнить ванну через соломинку для
питья холодных напитков?
28. [3] В каких единицах измеряется время доступа к жесткому диску: в миллисекундах
(тысячных долях секунды) или микросекундах (миллионных долях секунды)? Сколько
времени занимает доступ к слову в оперативной памяти вашего компьютера: больше
или меньше микросекунды? Сколько инструкций может выполнить центральный про-
цессор вашего компьютера в течение года, если компьютер постоянно держать вклю-
ченным?
29. [4] Алгоритм сортировки выполняет сортировку 1000 элементов за 1 секунду. Сколько
времени займет сортировка 10 000 элементов:
• если время исполнения алгоритма прямо пропорционально n2?
• если время исполнения алгоритма, по грубым оценкам, пропорционально nlogn?
Проекты по реализации
30. [5] Реализуйте два эвристических алгоритма решения задачи коммивояжера из разд. 1.1.
Какой из них выдает на практике более качественные решения? Можете ли вы предло-
жить эвристический алгоритм, работающий лучше любого из них?
31. [5] Опишите способ проверки достаточности покрытия тем или иным множеством ком-
бинаций номеров лотерейных билетов из задачи в разд. 1.6. Напишите программу поис-
ка хороших множеств комбинаций номеров билетов.
Задачи, предлагаемые на собеседовании
32. [5] Напишите функцию деления целых чисел, которая не использует ни оператор деле-
ния (/), ни оператор умножения (*). Функция должна быть быстродействующей.
33. [5] У вас есть 25 лошадей. В каждой скачке может участвовать не больше 5 лошадей.
Требуется определить первую, вторую и третью по скорости лошадь. Найдите мини-
мальное количество скачек, позволяющих решить эту задачу.
34. [3] Сколько настройщиков пианино во всем мире?
35. [3] Сколько бензоколонок в Соединенных Штатах?
36. [3] Сколько весит лед на хоккейном поле?
37. [3] Сколько километров дорог в Соединенных Штатах?
38. [3] Сколько раз в среднем нужно открыть наугад телефонный справочник Манхэттена,
чтобы найти определенного человека?
54 Часть I. Практическая разработка алгоритмов
LeetCode
LeetCode — это веб-сайт, на котором люди могут попрактиковаться в решении задач коди-
рования и подготовиться к техническим собеседованиям:
1. https://leetcode.com/problems/daily-temperatures/
2. https://leetcode.com/problems/rotate-list/
3. https://leetcode.com/problems/wiggle-sort-ii/
HackerRank
HackerRank — это социальная платформа, которая предлагает задания разной сложности по
программированию:
1. https://www.hackerrank.com/challenges/array-left-rotation/
2. https://www.hackerrank.com/challenges/kangaroo/
3. https://www.hackerrank.com/challenges/hackerland-radio-transmitters/
Задачи по программированию
Эти задачи доступны на сайте http://uva.onlinejudge.org. Так как сайты англоязычные, на-
звания задач даются на исходном языке:
1. «The 3n + 1 problem», глава 1, задача 100.
2. «The Trip», глава 1, задача 10137.
3. «Australian Voting», глава 1, задача 10142.
ЧАСТЬ II
Каталог
алгоритмических задач
ГЛАВА 14
Описание каталога
Вторая часть книги содержит каталог алгоритмических задач, которые часто возни-
кают на практике. Здесь приводится общая информация по каждой задаче и даются
советы, как действовать, если та или иная задача возникнет в вашем приложении.
Как использовать этот каталог? Если вы знаете название своей задачи, то с помощью
алфавитного указателя или оглавления найдите ее описание. Прочитайте весь матери-
ал, относящийся к задаче, поскольку он содержит ссылки на связанные с ней задачи.
Пролистайте каталог, изучая рисунки и названия задач. Возможно, что-то покажется
подходящим для вашего случая. Смело пользуйтесь алфавитным указателем — каждая
задача внесена в него несколько раз под разными ключевыми словами.
Каталог содержит обширную информацию разных типов, которая никогда раньше не
собиралась в одном месте.
Каждая задача сопровождается рисунком, представляющим входной экземпляр задачи
и результат его решения. Эти стилизованные примеры иллюстрируют задачи лучше,
чем формальные описания. Так, пример, касающийся минимального остовного дерева,
демонстрирует кластеризацию точек с помощью минимальных остовных деревьев.
Я надеюсь, что после беглого просмотра рисунков вы сможете найти то, что вам нужно.
Если вы нашли подходящую для вашего приложения задачу, прочитайте раздел «Об-
суждение». В нем описаны ситуации, в которых может возникнуть эта задача, и осо-
бые случаи входных данных, а также рассказано, какой результат можно разумно ожи-
дать и, что еще более важно, как его добиться. Для каждой задачи приводятся краткое
описание несложного решения, которым можно ограничиться в простых случаях,
и ссылки на более мощные алгоритмы, чтобы вы могли ими воспользоваться, если
первое решение окажется недостаточно эффективным.
Кроме того, приведены существующие программные реализации. Многие из этих про-
цедур весьма удачны, и их код можно вставлять непосредственно в ваше приложение.
Другие могут не отвечать требованиям промышленного применения, но я надеюсь, что
они послужат хорошей моделью для вашей собственной реализации. Вообще, про-
граммные реализации приведены в порядке убывания их ценности, но при наличии
бесспорно лучшего варианта я явно отмечаю его. В главе 22 для многих из этих реали-
заций дается более подробная информация. Практически для всех реализаций на сайте
этой книги (www.algorist.com) даются ссылки для их загрузки.
Наконец, в примечаниях к задаче рассказывается ее история и приводятся результаты,
представляющие в основном теоретический интерес. Я постарался описать наилучшие
известные результаты для каждой задачи и дать ссылки на работы по теоретическому и
эмпирическому сравнению алгоритмов, если таковые имеются. Эта информация долж-
496 Часть II. Каталог алгоритмических задач
на представлять интерес для студентов, исследователей и практиков, не удовлетворив-
шихся рекомендуемыми решениями.
14.1. Предостережения
Приведенный в этой части материал является каталогом алгоритмических задач, а не
сборником рецептов, поскольку существует слишком много различных задач и вариан-
тов их решений. Моя цель — указать вам правильное направление, чтобы вы могли
решать свои задачи самостоятельно. Я попытался лишь очертить круг вопросов, с ко-
торыми вы столкнетесь в процессе решения задач.
Для каждой задачи я дал рекомендацию, какой алгоритм следует использовать. Эти
советы основаны на моем опыте и касаются приложений, которые я считаю типич-
ными. При работе над книгой я полагал, что гораздо лучше дать конкретные реко-
мендации для типичных случаев, чем пытаться охватить все возможные ситуации.
Если вы не согласны с моим советом, вы не обязаны следовать ему. Однако поста-
райтесь понять идеи, лежащие в основе моих советов, чтобы вы могли сформулиро-
вать причину, по которой ваши требования не соответствуют моим предположени-
ям.
Рекомендуемые мною реализации не обязательно являются исчерпывающими ре-
шениями вашей задачи. Некоторые программы пригодны только в качестве моделей
для создания вашего собственного кода. Другие встроены в большие системы, и их
может быть слишком трудно извлечь и исполнять отдельно. Все эти решения со-
держат ошибки. Многие из таких ошибок могут оказаться довольно серьезными, так
что будьте начеку.
Вы обязаны соблюдать условия лицензии любой реализации, которую вы исполь-
зуете в коммерческих целях. Многие из этих программ не являются свободно рас-
пространяемыми, и большинство имеет лицензионные ограничения. Подробности
см. в разд. 22.1.
Мне бы хотелось узнать о результатах, полученных вами при следовании моим
рекомендациям, — как о положительных, так и об отрицательных. Особый интерес
для меня представляет информация о других реализациях, неизвестных мне, но из-
вестных вам.
ГЛАВА 15
Структуры данных
Структуры данных — это базовые конструкции для построения приложений. Чтобы
максимально полно использовать возможности стандартных структур данных, необхо-
димо иметь о них ясное представление. Поэтому мы сначала подробно рассмотрим
различные структуры данных, а затем перейдем к обсуждению других задач.
На мой взгляд, наиболее важным аспектом этого раздела каталога станут предостав-
ленные в нем ссылки на разные программные реализации и библиотеки структур дан-
ных. Хорошая реализация многих структур данных — дело далеко не тривиальное,
поэтому программы, на которые даются ссылки, окажутся вам полезными в качестве
моделей, даже если они и не в точности подходят для ваших задач. Некоторые важные
структуры данных, такие как kd-деревья и суффиксные деревья, известны не настолько
хорошо, насколько они того заслуживают. Будем надеяться, что этот раздел каталога
добавит им известности.
Существует большое количество книг по элементарным структурам данных. На мой
взгляд, лучшими из них являются следующие:
[SW11] — подробное введение в алгоритмы и структуры данных отличающееся
удачными рисунками, показывающими алгоритмы в действии. Имеются версии
книги для языков C, C++ и Java;
[Wei11] — хороший учебник, с упором на структуры данных в большей степени,
чем на алгоритмы. Имеются версии книги для языков Java, C, C++ и Ada;
[GTG14] — версия книги для Java с активным использованием авторской библиоте-
ки структур данных JDSL (Java Data Structures Library);
[Bra08] — хорошее рассмотрение более продвинутых структур данных, чем те, ко-
торые рассматриваются в других учебниках с реализацией на языке C++.
Книга [MS18] содержит всесторонний обзор современных исследований в области
структур данных. Читатель, знакомый лишь с основными понятиями из этой области,
будет удивлен объемом проводимых исследований.
15.1. Словари
Вход. Множество из n записей, каждая из которых идентифицируется одним или не-
сколькими ключами.
Задача. Создать и поддерживать структуру данных для эффективного поиска, вставки
и удаления записи, связанной с ключом запроса q (рис. 15.1).
498 Часть II. Каталог алгоритмических задач
Словарь
Вход Выход
Рис. 15.1. Поиск в словаре
Обсуждение
Абстрактный тип данных «словарь» (dictionary) является одной из наиболее важных
структур в теории вычислительных систем. Для реализации словарей было предложено
несколько десятков структур данных, включая хеш-таблицы, списки с пропусками и
двоичные деревья поиска. Это означает, что выбрать наилучшую структуру данных не
всегда легко. Однако на практике важнее избежать применения неподходящей
структуры данных, чем найти самую лучшую.
Вы должны тщательно изолировать словарную структуру данных от ее интерфейса.
Используйте явные вызовы методов или процедур для инициализации, поиска и моди-
фицирования структуры данных, а не внедряйте их в код структуры. Такой подход не
только позволяет получить более аккуратную программу, но также облегчает проведе-
ние экспериментов с разными реализациями для оценки их производительности. Не
озабочивайтесь по поводу неизбежных накладных расходов по вызову процедур. Если
время работы вашего приложения является очень серьезным фактором, то такие экспе-
рименты важны тем, что помогут вам выбрать правильную реализацию словаря, чтобы
минимизировать его.
Выбирая структуру данных для словаря, ответьте на несколько вопросов.
Сколько элементов будет содержать структура данных?
Известно ли их количество заранее? Достаточно ли будет для решения вашей зада-
чи простой структуры данных, или же размер задачи настолько велик, что следует
беспокоиться о нехватке памяти или производительности виртуальной памяти?
Известна ли относительная частота операций вставки, удаления и поиска?
Статические структуры данных (например, упорядоченные массивы) достаточны
для приложений, в которых структура данных не подвергается изменениям после ее
первоначального создания. Полудинамические структуры данных, поддерживаю-
щие только операцию вставки и не допускающие удаление данных, реализовать
значительно проще, чем полностью динамические.
Глава 15. Структуры данных 499
Будет ли обращение к ключам единообразным и случайным?
Во многих приложениях поисковые запросы имеют асимметричное распределение
обращений, т. е. некоторые элементы пользуются большей популярностью, чем
другие. Кроме того, запросы часто обладают свойством временно´й локальности.
Иными словами, запросы периодически приходят группами (кластерами), а не через
регулярные интервалы времени. В структурах данных типа косых деревьев можно
воспользоваться асимметричным и кластеризированным пространством.
Критична ли скорость каждой отдельной операции или требуется минимизиро-
вать только общий объем работы, выполняемый всей программой?
Когда время реакции критично — например, в программе управления аппаратом
искусственного кровообращения, время ожидания выполнения следующего шага не
может быть слишком большим. А при выполнении множества запросов к базе дан-
ных — например, для выяснения, кто из нарушителей закона является политиче-
ским деятелем, скорость поиска конкретного законодателя не является критичной,
если удается выявить их всех с минимальными общими затратами времени.
Представители современного поколения «объектно-ориентированных» программистов
способны написать контейнерный класс не в большей степени, чем отремонтировать
двигатель в своей машине. В этом нет ничего плохого — для большинства приложений
вполне достаточно стандартных контейнеров. Тем не менее иногда полезно знать, что
именно находится «под капотом»:
неупорядоченные списки или массивы.
Для небольших наборов данных самой простой в обслуживании структурой будет
неупорядоченный массив. По сравнению с аккуратными и компактными массивами
производительность связных структур может быть крайне неудовлетворительной.
Но когда размер словаря превысит 50–100 элементов, линейное время поиска в спи-
ске или массиве сведет на нет все его преимущества.
Особенно интересным и полезным вариантом является самоорганизующийся список
(self-organizing list), в котором вставляемый или просматриваемый элемент переме-
щается в начало списка. Таким образом, если в ближайшем будущем к тому или
иному ключу осуществляется повторное обращение, то этот ключ будет находиться
вблизи начала списка и его поиск займет очень мало времени. Большинство прило-
жений демонстрируют как неоднородную частоту обращений, так и пространствен-
ную локальность, поэтому среднее время успешного поиска в самоорганизующемся
списке обычно намного меньше, чем в упорядоченном или неупорядоченном спи-
ске. Самоорганизующиеся структуры данных можно создавать из массивов точно
так же, как из связных списков и деревьев;
упорядоченные списки или массивы.
Обслуживание упорядоченного списка обычно не стоит затрачиваемых усилий, по-
скольку эта структура данных не поддерживает двоичный поиск, — если только вы
не пытаетесь избежать создания дубликатов. Использование упорядоченного масси-
ва будет уместным только в тех случаях, когда не требуется выполнять большое
количество вставок и/или удалений;
500 Часть II. Каталог алгоритмических задач
хеш-таблицы.
Для приложений, работающих с количеством элементов в диапазоне от умеренного
до большого, использование хеш-таблицы будет, скорее всего, правильным выбо-
ром. Хеш-функция устанавливает соответствие ключей (будь то строки, числа или
что угодно другое) и целых чисел в диапазоне от 0 до m – 1. Создание хеш-таблицы
сопровождается массивом из m корзин, реализованных в виде неупорядоченного
связного списка. Хеш-функция немедленно определяет корзину, содержащую иско-
мый ключ. Если используемая хеш-функция распределяет ключи достаточно равно-
мерно в хеш-таблице достаточно большого размера, то каждая корзина будет содержать
очень небольшое количество элементов, что делает линейные поиски приемлемы-
ми. Вставка и удаление элемента из хеш-таблицы сводится к вставке и удалению из
корзины/списка. Хеширование подробно обсуждалось в разд. 3.7.
В большинстве приложений производительность хорошо отлаженной хеш-таблицы
будет превосходить производительность упорядоченного массива. Но прежде чем
приступить к реализации хеш-таблицы, ответьте на несколько вопросов.
• Каким образом обрабатывать коллизии?
Использование открытой адресации вместо корзин позволит получить неболь-
шие таблицы с хорошей производительностью, но при слишком высоком коэф-
фициенте нагрузки (отношение заполненности к емкости) производительность
хеш-таблицы будет понижаться.
• Каким должен быть размер таблицы?
Если задействуются корзины, то значение m должно быть приблизительно рав-
ным максимальному количеству элементов, которое вы планируете поместить
в таблицу. Если применяется открытая адресация, то значение m должно превы-
шать ожидаемое максимальное количество элементов, по крайней мере, на 30–
50%. Выбор в качестве m простого числа компенсирует возможные недостатки
неудачной хеш-функции.
• Какую хеш-функцию использовать?
Для строк должна работать, например, такая формула:
S −1
∑H ( S ) = α S + α S −(i+1) × char (si )(mod m),
i=0
где α — размер алфавита; char(x) — функция, которая для каждого символа x
возвращает его код. Для реализации эффективного вычисления этой хеш-
функции используйте правило Горнера (или заранее вычисляйте значения αx),
как показано в разд. 16.9. Версия этой хеш-функции (см. разд. 6.7) обладает од-
ним интересным свойством, заключающимся в том, что хеш-коды последова-
тельных окон строки размером в k символов можно вычислять за постоянное
время, а не за время O(k).
При оценке эффективности используемой хеш-функции изучите статистические
данные относительно распределения ключей по корзинам, чтобы выяснить, на-
сколько она действительно является однородной. Вероятно, что самая первая вы-
Глава 15. Структуры данных 501
бранная хеш-функция окажется не самой лучшей. Использование неудачной хеш-
функции может заметно снизить производительность любого приложения;
двоичные деревья поиска.
Двоичные деревья представляют собой элегантные структуры данных, которые
поддерживают быстрое исполнение операций вставки, удаления и запросов
(см. разд. 3.4). Главное отличие между разными типами деревьев проявляется в том,
выполняется ли их балансировка явным образом после операций вставки и удале-
ния и в способе ее осуществления. В простых произвольных деревьях поиска каж-
дый узел вставляется в некий лист дерева и повторная балансировка не осуществля-
ется. Хотя такие деревья имеют хорошую производительность в случае произволь-
ных вставок, большинство приложений не обеспечивают случайность вставок.
И действительно, несбалансированные деревья поиска, созданные вставками эле-
ментов в отсортированном порядке, никуда не годятся, поскольку их производи-
тельность ухудшается до производительности связных списков.
Структура сбалансированных деревьев поиска обновляется с помощью локальных
операций ротации, которые перемещают удаленные узлы ближе к корню, таким
образом поддерживая упорядоченную структуру дерева. В настоящее время такие
сбалансированные деревья поиска, как AVL и 2/3, считаются устаревшими, и наи-
большее предпочтение отдается красно-черным деревьям. Особенно интересной са-
моорганизующейся структурой данных являются косые деревья. В них ключи, к ко-
торым было осуществлено обращение, перемещаются в корень посредством опера-
ции ротации. В результате часто используемые или недавно посещенные узлы
находятся в верхней части дерева, что позволяет быстрее производить поиск.
Итак, какой тип дерева лучше всего подойдет для вашего приложения? Наверное,
тот, для которого у вас имеется наилучшая реализация. Не так важен тип исполь-
зуемого сбалансированного дерева, как профессионализм программиста, реализо-
вавшего его;
B-деревья.
Для наборов данных настолько больших, что они не помещаются в оперативную
память, наилучшим выбором будет какой-либо тип B-дерева. Когда структура дан-
ных хранится вне оперативной памяти, время поиска увеличивается на несколько
порядков. Подобное падение производительности в меньшем масштабе может на-
блюдаться в системах с современной архитектурой кэша, поскольку кэш работает
намного быстрее, чем оперативная память.
Идея, лежащая в основе B-дерева, состоит в сворачивании нескольких уровней дво-
ичного дерева поиска в один большой узел, чтобы можно было выполнить опера-
цию, эквивалентную нескольким шагам поиска, прежде чем потребуется новое
обращение к диску. С помощью B-деревьев можно получать доступ к огромному
количеству ключей, выполняя небольшое количество обращений к диску. Чтобы
максимально эффективно использовать B-деревья, нужно понимать, как взаимодей-
ствуют внешние запоминающие устройства с виртуальной памятью, — в частности,
такие аппаратные характеристики, как размер страницы и виртуальное/реальное ад-
ресное пространство. Нечувствительные к кэшированию алгоритмы (cache-oblivious
algorithms) позволяют уменьшить значение этих факторов.
502 Часть II. Каталог алгоритмических задач
Даже в случае наборов данных небольшого размера результатом использования
файлов подкачки может быть неожиданно низкая производительность, поэтому не-
обходимо следить за интенсивностью обращений к жесткому диску, чтобы полу-
чить дополнительную информацию для принятия решения, стоит ли использовать
B-деревья;
списки с пропусками.
Списки с пропусками представляют собой иерархическую структуру упорядочен-
ных связных списков, в которых решение, копировать ли элемент в список более
высокого уровня, принимается случайным образом. В структуре задействовано
примерно lg n списков, и размер каждого из них приблизительно вдвое меньше раз-
мера списка, расположенного уровнем выше. Поиск начинается в самом коротком
списке. Искомый ключ находится в интервале между двумя элементами и потом
ищется в списке большего размера. Каждый интервал поиска содержит ожидаемое
постоянное количество элементов в каждом списке, при этом общее ожидаемое
время исполнения запроса составляет O(lg n). Основные достоинства списков
с пропусками по сравнению со сбалансированными деревьями — легкость анализа
и реализации.
Реализации
Современные языки программирования содержат библиотеки подробных и эффектив-
ных реализаций контейнеров. В настоящее время с большинством компиляторов для
языка С++ поставляется библиотека STL (Standard Template Library). Более подробное
руководство по использованию библиотеки STL и стандартной библиотеки С++ можно
найти в книгах [Jos12], [Mey01] и [MDS01]. Небольшая библиотека структур данных
Java Collections (JC) входит в стандартный пакет утилит Java java.util.
Библиотека LEDA (см. раз. 22.1.1) предоставляет полную коллекцию словарных струк-
тур данных, реализованных на языке С++, включая хеш-таблицы, совершенные хеш-
таблицы, B-деревья, красно-черные деревья, деревья случайного поиска и списки
с пропусками. В результате экспериментов, описанных в книге [MN99], было опреде-
лено, что наилучшим вариантом для словарей являются хеш-таблицы, а списки с про-
пусками и (2,4)-деревья (частный случай B-деревьев) являются наиболее эффективны-
ми древоподобными структурами.
ПРИМЕЧАНИЯ
В книге [Knu97a] представлено наиболее подробное описание и анализ основных словар-
ных структур данных. Но в ней отсутствуют некоторые современные структуры данных,
такие как красно-черные и косые деревья. Чтение книг Дональда Кнута послужит хоро-
шим введением в предмет для всех изучающих теорию вычислительных систем.
В книге [MS18]] дан всесторонний обзор современных исследований в области структур
данных. Другие исследования представлены в книгах [MT90b] и [GBY91]. Хорошими
учебниками по словарным структурам данных являются [Sed98], [Wei11] и [GTG14]. Мы
отсылаем читателя к этим работам, чтобы не приводить здесь ссылки на описания струк-
тур данных, обсуждавшихся ранее.
Соревнование DIMACS в 1996 году было посвящено реализациям элементарных структур
данных, включая словари (см. [GJM02]). Наборы данных и код можно загрузить с веб-
сайта http://dimacs.rutgers.edu/Challenges.
Глава 15. Структуры данных 503
Для многих задач стоимость обмена данными между различными запоминающими уст-
ройствами (оперативной памятью, кэшем или диском) превышает стоимость собственно
вычислений. В каждой операции по пересылке данных перемещается один блок размером b,
поэтому эффективные алгоритмы стремятся минимизировать количество перемещений
блоков. Исследование сложности фундаментальных алгоритмов и структур данных для
этой модели внешней памяти представлено в журнале [Vit01]. Нечувствительные к кэши-
рованию структуры данных дают гарантию производительности для такой модели, не тре-
буя при этом явной информации о параметре размера блока b. Таким образом, хорошую
производительность можно получить на любой машине, не прибегая к специфическим для
ее архитектуры настройкам. Превосходное исследование структур данных, не чувстви-
тельных к кэшированию, приведено в [ABF05] и [Dem02].
Косые деревья и другие современные структуры данных изучались с применением амор-
тизированного анализа, при котором устанавливается верхняя граница для общего време-
ни исполнения любой последовательности операций. При амортизированном анализе
одна операция может быть очень дорогой, но только потому, что ее стоимость компенси-
руется низкими затратами на другие операции. Структура данных, имеющая амортизиро-
ванную сложность O(f(n)), является менее предпочтительной, чем структура с такой же
сложностью в наихудшем случае (поскольку существует вероятность выполнения очень
дорогой операции), но она все же лучше структуры с такой сложностью в среднем случае
(т. к. амортизированная граница достигнет этого значения при любом входе).
Родственные задачи
Сортировка (см. разд. 17.1), поиск (см. разд. 17.2).
15.2. Очереди с приоритетами
Вход. Набор записей, ключи которых полностью упорядочены.
Задача. Создать и поддерживать структуру данных для обеспечения быстрого доступа
к наименьшему или наибольшему ключу (рис. 15.2).
Вход Выход
Рис. 15.2. Очередь с приоритетами
ПРИЛОЖЕНИЕ
Описание
электронного архива
Электронный архив, сопровождающий книгу, можно скачать с FTP-сервера издатель-
ства «БХВ» по адресу: https://zip.bhv.ru/9785977567992.zip. Ссылка на него доступна и
со страницы книги на сайте https://bhv.ru/.
В архиве содержатся:
файл Рисунки.pdf, содержащий все рисунки книги в том виде, как они приведены
в полноцветном исходном ее издании (с переводом на русский язык некоторых
нуждающихся в этом надписей);
файл Листинги с цветными элементами.pdf, содержащий все листинги книги, содер-
жащие цветные элементы, в том виде, как они приведены в полноцветном исходном
ее издании.
Предметный указатель
A GLPK 546
GMP, библиотека 559
agrep 765 GnuPG 775
GOBLIN, библиотека 640
B Grail+ 778
gzip 769
BioJava 510
Boost Graph Library, библиотека 514 I
Boost, библиотека 787
BSP-дерево 521 ILOG CP 604
B-дерево 501
J
C
JAMA, библиотека 537
Calendrical 601 JC, библиотека 502
CALGO 788 JFKAP 778
Chaco 674 JGraphT, библиотека 514, 613
Cliquer 657 JOBSHOP 604
CLP, библиотека 546 JScience, библиотека 537
Cocone 730 JUNG, библиотека 514, 613
Combinatorica 244, 789
Core, библиотека 697 K
Crypto++, библиотека 775
Cтруктурs данных 95 KDTREE 2 523
Cуффиксные деревья 497 Kd-деревья 497, 520
D L
DSATUR 677 LEKIN 604
LIBSVM, библиотека 740
F LINPACK 537
lp_solve 545
FFTPACK, библиотека 567
FFTW, библиотека 567 M
FLUTE 688
Mathematica 244
G METIS 674
MINCUTLIB 640
GEOMPACK 733 MIRACL, библиотека 554
GeoSteiner 688
840 Предметный указатель
N А
NEOS 542, 546 Ависа — Фукуды, алгоритм 701
Netlib, библиотека 788 Автоморфизм 681
Nettle, библиотека 775 Аксиома треугольника 445, 665
NTL, библиотека 554 Алгоритм 25
◊ Soundex 765
P ◊ Ависа — Фукуды 701
◊ Ахо — Корасика 759
PARI 554 ◊ Беллмана — Форда 624
PAUP 688 ◊ ближайшего соседа 27
PHYLIP 688 ◊ ближайших пар 28
PIGALE 654 ◊ Бойера — Мура 759
Powercrust 730, 737 ◊ Борувки 619
Prolog, язык 390 ◊ генетический 471
◊ Гровера 475
Q ◊ Грэхема 700
◊ Дейкстры 299, 301, 623
Qhull 701, 705, 709 ◊ Дугласа — Пекера 736
QSlim 736 ◊ заворачивания подарка 699
◊ заметающей прямой 705
R ◊ Карацубы 191
◊ Кнута — Морриса — Пратта 759
RAM 55 ◊ Кристофидеса 446, 447
RAM-машина 55 ◊ Крускала 288, 618
RAM-модель 55 ◊ Крускала 290
REDUCE 519 ◊ Лас-Вегас 207
Roncorde 667 ◊ Лемпеля — Зива 769
Rонтейнеры 95 ◊ Монте-Карло 207, 227, 316
◊ поиска подстроки в строке 225
S ◊ поразрядной сортировки (radix sort) 172
◊ Прима 285, 286, 300, 618
Scotch 674 ◊ Рабина — Карпа 225, 315
Soundex, алгоритм 765 ◊ «разделяй и властвуй» 194
SourceForge 788 ◊ сортировки методом Шелла (shellsort)
Spatial Index Demos 523
SPRNG, библиотека 551 172
Stanford GraphBase 789 ◊ сортировки слиянием 172, 181
STL, библиотека 502 ◊ тасования Фишера — Йейтса 585
strmat 510, 760 ◊ Укконена 510
SYMPHONY 754, 757 ◊ Флойда — Уоршелла 302, 304, 625
◊ Форчуна 707
T ◊ Хиршберга 764
◊ Шора 478
TRE, библиотека 765 ◊ Эдмондса — Карпа 314
TSPLIB, библиотека 667 Альфа-очертания 700
Анаграмма 349
V Аналогии 49
Арифметическая прогрессия 72
VRONI 730 Арифметические операции 557
Асимптотические обозначения 58, 59, 61
Асимптотическая нотация 58
Предметный указатель 841
Б Вырожденность 694
Вырожденные системы уравнений 527
Базовые объекты 44 Высота двоичных деревьев поиска 112
Бесконтурные графы 612
Беспорядок (derangement) 347 Г
Библиотека
◊ Boost 787 Гамильтонов путь 117
◊ Boost Graph Library 514 Гамильтонов цикл 410, 423, 668
◊ CLP 546 Гармоническое число 76
◊ Core 697 Генератор
◊ Crypto++ 775 ◊ псевдослучайных чисел 230
◊ FFTPACK 567 ◊ случайных чисел 229, 547
◊ FFTW 567 Генетические алгоритмы 471
◊ GMP 559 Геометрическая прогрессия 72
◊ GOBLIN 640 Геометрическое распределение 216
◊ JAMA 537 Гиперграф 513
◊ JC 502 Грамматика контекстно-свободная 384
◊ JGraphT 514, 613 Граничные ошибки 39
◊ JScience 537 Граф 41, 233, 234, 595
◊ JUNG 514, 613 ◊ ациклический 236
◊ LIBSVM 740 ◊ бесконтурный подграф 449
◊ MIRACL 554 ◊ вершинная раскраска 675
◊ Netlib 788 ◊ вершинное покрытие 278, 412, 419, 441,
◊ Nettle 775
◊ NTL 554 661
◊ SPRNG 551 ◊ взвешенный 235, 238, 283
◊ STL 502 ◊ гамильтонов цикл 410, 668
◊ TRE 765 ◊ гиперграф 513
◊ TSPLIB 667 ◊ двудольный 258, 310
Биномиальные коэффициенты 358 ◊ доминирующее множество 662
Биноминальное распределение 212 ◊ изоморфизм 680
Блочная сортировка (bucket sort) 168 ◊ квадрат 278
Борувки, алгоритм 619 ◊ клика 415
Быстрая сортировка (quicksort) 138 ◊ кратное ребро 235
Быстрое преобразование Фурье 476 ◊ кратчайший путь 622
◊ матрица инцидентности 513
В ◊ минимальное остовное дерево 617
◊ мост 268
Вершинная раскраска 675 ◊ независимое множество 413, 463
Вершинное покрытие 410, 412, 419, 441, 661 ◊ неориентированный 237
Взвешенные графы (weighted graph) 283 ◊ неявный 236
Взятие адреса 98 ◊ обход 250
Возведение в степень 75 ◊ ориентированное дерево 281
Вороного, диаграмма 706 ◊ ориентированный 234, 237
Восстановление ◊ остаточного потока (residual flow graph)
◊ пирамиды (heapify) 150
◊ пути 364 311
Восхождение по выпуклой поверхности 456 ◊ остовное дерево 284
Выпуклая оболочка 140, 409, 698 ◊ паросочетание 310
Выпуклые функции 540 ◊ перечисление путей 330
◊ петля 235
◊ планарный 512
842 Предметный указатель
Граф (прод.) ◊ рисование 649
◊ плотный 235, 238 ◊ сбалансированное 113
◊ полный 236 ◊ суффиксное 507
◊ помеченный 237 ◊ удаление элемента 112
◊ простой 238 ◊ Штейнера 294, 617, 685
◊ путь 255 Деревья 236
◊ разреженный 235 Диаграмма
◊ разрывающее множество 689 ◊ Вороного 706
◊ раскраска вершин 257 ◊ Ганта 605
◊ реберное покрытие 323, 663 ◊ Феррера 593
◊ рисование 644 Диапазонный запрос 714
◊ связность 264, 610, 638 Динамическое
◊ связный 256 ◊ выделение памяти 96, 101
◊ сильно связный 272 ◊ программирование 181, 352
◊ список смежности 283 Дискретное преобразование Фурье 565
◊ степень вершины 238 Доказательство
◊ топологическая сортировка 236, 270 ◊ алгоритма 33
◊ транзитивное замыкание 304 ◊ сложности 423
◊ турнир 281 Доминирование функции 63, 84
◊ укладка 236 Доминирующее множество 662
◊ цикл 263 Дополнение графа 659
◊ шарнир 264 Древесное ребро 443
◊ Эйлеров подграф 436 Дугласа — Пекера, алгоритм 736
◊ Эйлеров цикл 436
График охлаждения 460 З
Грея, код 588
Грэхема, алгоритм 700 Задача
◊ 3-SAT 417, 426
Д ◊ безусловной оптимизации 575
◊ вершинной раскраски 675
Двоичное дерево 74 ◊ внешней сортировки 572
Двоичные пирамиды 505 ◊ выполнимости 605
Двоичный поиск 73, 181, 576
Дейкстры, алгоритм 299, 623 булевых формул 416, 605
Демонстрация доказательства 33 ◊ выявления изоморфизма графов 680
Дерево 41, 74 ◊ выявления сходства фигур 737
◊ BSP-дерево 521 ◊ календарного планирования 30, 413, 601
◊ B-дерево 501 ◊ китайского почтальона 634
◊ kd-дерево 520 ◊ коммивояжера 30, 352, 387, 664
◊ вставка элемента 111 ◊ линейного расположения 531
◊ двоичное 74, 108 ◊ максимального разреза 463
◊ квадродерево 521 ◊ минимизации профиля 531
◊ косое 501 ◊ нечеткого сравнения строк 360, 761
◊ минимальное остовное 617 ◊ о вершинном покрытии 412, 419, 441,
◊ наибольший элемент 110
◊ обход 110 661
◊ октадерево 521 ◊ о доминирующем множестве 662
◊ остовное 284 ◊ о клике 415
◊ поиска 108 ◊ о минимальном множестве
◊ помеченное 597
представителей 752
◊ о назначениях 631
◊ о независимом множестве 413
Предметный указатель 843
◊ о покрытии множества 750 К
◊ о потоках в сетях 309, 641
◊ о разрывающем множестве 689 Календарное планирование 30, 601
◊ о реберном покрытии 663 Календарь 599
◊ о рюкзаке 376, 560 Каноникализация 125
◊ о сумме подмножества 562 Каркас транзитивного замыкания 630
◊ оптимизации 538 Квадратный корень 184
◊ планирования перемещений 741 Квадродерево 521
◊ поиска ближайшего соседа 710 Классы
◊ поиска ближайшей пары 406 ◊ абстрактных типов данных 95
◊ поиска в области 714 ◊ ребер неориентированного графа 261
◊ поиска гамильтонова цикла 410, 668 Клика 656
◊ поиска компонентов связности 610 Код
◊ поиска кратчайшего пути 622 ◊ Грея 588, 669
◊ поиска медианы 580 ◊ Прюфера 597
◊ поиска эйлерова цикла 634 ◊ Хаффмана 768
◊ построения выпуклой оболочки 698 Коллизия 121, 122
◊ построения дерева Штейнера 685 Компонент связности 256, 610
◊ преобразования к срединной оси 728 Конечный автомат 776
◊ разбиения графа 672 Контейнер 101
◊ разбиения многоугольника на части 732 Контекстно-свободная грамматика 384
◊ разбиения множества целых чисел 562 Контрольная сумма 773
◊ раскроя 725 Контрпримеры 35
◊ реберной раскраски 679 Конфигурации прямых 745
◊ рисования графа 644 Конфликт имен файлов 318
◊ рисования дерева 649 Косое дерево 501
◊ сортировки 25, 56 Коэффициент сходства Жаккара 222
◊ сравнения строк 758 Красно-черные деревья 501
◊ укладки множества 755 Кратчайший путь 622
◊ упорядоченного разбиения Криптографическое хеширование 124
Криптография 770
(ordered partition) 381 Крускала, алгоритм 288, 618
◊ упрощения многоугольников 735 Кэширование 354
Задачи разрешимости (decision problems 405 ◊ результатов вычислений 356
Закон
◊ Кирхгофа 527 Л
◊ Мура 246
◊ Ципфа 576 Лагранжева релаксация 541
Запоминание (сохранение) результатов Лексикографический порядок 583, 588
Лемпеля — Зива, алгоритм 769
(memoization) 355 Ленточная матрица 528
Линейное программирование 542
И Линейное расширение 614
Линейный конгруэнтный генератор 229,
Идентичность графов 681
Изоморфизм графов 680 549
Имитация отжига 459 Логарифм 73
Индекс 96 ◊ двоичный 78
Интерполяционный поиск 578 ◊ десятичный 78
Использование ◊ натуральный 78
◊ «жадного» эвристического алгоритма 118 Локальный поиск 455
◊ циклического избыточного кода 773
844 Предметный указатель
М Множество 515, 750
◊ пересечение 141
Максимально монотонная ◊ разбиение 517
подпоследовательность 370 Мода 581
Моделирование задачи 40
Максимальное независимое множество 660 Модель
Малая теорема Ферма 227 ◊ вычислений RAM 55
Массив 96 ◊ Эрдёша — Реньи 596
◊ разбиение на части 161 Мост 638
Математическая индукция 38 Мультимножество 585
Матрица смежности 240, 511
Матрицы: умножение 70 Н
Матроиды (matroids) 621
Машина с произвольным доступом Нагруженное дерево 507
Наибольший общий делитель 408
к памяти (Random Access Machine, RAM) Наименьшее общее кратное 408
55 Невзвешенные графы (unweighted graphs)
Медиана 579, 581
Местоположение 283
◊ точка 696, 716 Независимое множество 659
◊ точки на плоскости 716 ◊ вершин графа 413
Метод Неправильность алгоритма 35
◊ внутренней точки 544 Нормальная форма Хомского 385
◊ восхождения по выпуклой поверхности
О
456
◊ деления интервала пополам 184 Обход
◊ доказательства от противного 44 ◊ в глубину (depth-first search, DFS) 325
◊ Дэвиса — Путнама 606 ◊ в ширину (breadth-first search, BFS) 325
◊ идеального хеширования 220 Обход графа 250
◊ имитации отжига 459 ◊ в глубину 259
◊ инкрементального изменения 583 ◊ в ширину 251
◊ исключения Гаусса 527 Односторонний двоичный поиск 183, 577
◊ «лесного пожара» 730 Октадерево 521
◊ минимальных хеш-кодов Операция
◊ дополнения графа 415
(minwise hashing) 223 ◊ стягивания 315
◊ Монте-Карло 452 Оптимальное дерево двоичного поиска 576
◊ отпечатков пальцев 126 Оптимизация 538
◊ поиска «лучший-первый» (best-first) 343 Основная теорема 188
◊ полос 719 Основные типы графов 234
◊ произвольной выборки 452 Остовное дерево 284
◊ «разделяй и властвуй» 181 Открытая адресация 122
◊ ранжирования/деранжирования 583 Открытый ключ RSA 552
◊ табличного сохранения, tabling 355 Отношение доминирования 63, 84
Методические вычисления 49 Отсечение (pruning) 332
Методы Очереди с приоритетами 95
◊ машинного обучения 739 Очередь 102
◊ произвольной выборки 206 ◊ с приоритетами 115, 119, 504
◊ Якоби и Гаусса — Зейделя 528
Механизм обмена цветов 677
Минимальное остовное дерево 284, 617
Минковского, сумма 748
Многоугольник 42
◊ разбиение на части 731
Предметный указатель 845
П Псевдослучайные числа 548
Пузырьковый метод 150
Парадокс дня рождения 220 Путь 255, 298
Параллелизм на уровне данных 194
Паросочетание 310, 323, 447, 630 Р
Перебор с возвратом (backtracking) 324
Пересечение Разбиение 590
◊ множеств 141 ◊ множества 290, 517
◊ отрезков 720 ◊ целого числа 590
◊ прямой и отрезка 696 Разложение
◊ прямых 694 ◊ на множители 552
Перестановка 41, 329, 583 ◊ по контейнерам 724
Перманент 536 Размещение прямоугольников по корзинам
Петля 238
Пирамида 146 318
◊ вставка элемента 149 Разреженная матрица 528
◊ создание 148 Разрывающее множество 689
◊ удаление элемента 150 Разрывающие множества
Пирамидальная сортировка (heapsort) 138 ◊ вершин 615
Пирамидальное число 80 ◊ дуг 615
Планирование перемещений 741 Разыменование указателя 97
Площадь треугольника 696 Рандомизация 113, 165, 444
Подмножество 41, 587 Рандомизированные алгоритмы 58, 206, 217
Подстрока 509 Расстояние
Поиск 575 ◊ редактирования 360, 407
◊ ближайшего соседа 713 ◊ хаусдорфово 739
◊ ближайшей пары 406 ◊ Хемминга 738
◊ двоичный 108 Реберное покрытие 663
◊ локальный 455 Реберно-хроматическое число 679
◊ максимальной общей подстроки 779 Регулярные выражения 776
◊ минимальной общей надстроки 782 Рекуррентное соотношение 186
◊ подстроки 509 Рекурсивный алгоритм 181
Полиномиальное умножение 197 Рекурсивный объект 42
Порядок Рекурсия 38
◊ FIFO 102 Решето числового поля 553
◊ LIFO 101 Решеточные укладки 653
Последовательный поиск 576 Рисование
Поток в сети 309, 641 ◊ графа 644
Правило Горнера 500 ◊ дерева 649
Преобразование к срединной оси 728
Прикидка 49 С
Прима, алгоритм 285, 618
Примеры свертки 198 Самоорганизующиеся списки 577
Принцип Самоорганизующийся список (self-
◊ оптимальности 388
◊ «разделяй и властвуй» 168 organizing list) 499
Проверка числа на простоту 227, 552 Сбалансированное двоичное дерево 113,
Произвольная выборка 452
Процедура двоичного поиска 183 146
Прюфера, код 597 Сведение (reduction) 403
Прямолинейный скелет 729 Свертка 197
Свойства
◊ алгоритма 26
◊ контрпримеров 36
846 Предметный указатель
Связность графа 638 Т
Связные структуры данных 95
Селективная сборка 465 Текст, сжатие 766
Сервер комбинаторных объектов 586, 589 Теорема
Сжатие текста 766 ◊ Байеса 211
Сильно связный граф 611 ◊ Кука 432
Симметричное распределение 213 ◊ Менгера 639
Симплекс-метод 543 ◊ о зоне 747
Синтаксический разбор 384, 385 Теория вероятностей 207
Система линейных уравнений 527 Типы вершин 251
Слабо связный граф 611 Топологическая сортировка 236, 614
Словари 95 Точка 42
Словарь 102, 498 ◊ местоположение 696, 716
Сложность алгоритма 56 Транзитивная редукция 629
Случаи основной теоремы 189 Транзитивное замыкание 304, 628
Случайные переменные 211 Транспонированный граф 274
Случайные числа 547 Триангуляция 117, 702
Смежные структуры данных 95
Сортировка 570 У
◊ блочная 167
◊ быстрая 160 Увеличивающие пути 311, 312, 632
◊ вставками 25, 67, 154 Указатели 95, 97
◊ методом выбора 65, 145 Уменьшение ширины ленты 530
◊ пирамидальная 146 Умножение матриц 70, 532
◊ порядок 143 Уоринга, проблема 79
◊ распределением (distribution sort) 138, 168 Уплотнение данных 126
◊ слиянием 158 Упорядочивание последовательности 317
◊ топологическая 270, 614 Условная вероятность 210
Составные события 209 Устойчивые множества 659
Социальные сети 237
Список 98 Ф
◊ вставка элемента 99
◊ поиск элемента 98 Фибоначчи 353
◊ смежности 240, 283, 511 Фильтр Блума 218, 219, 517
◊ удаление элемента 99 Флойда — Уоршелла, алгоритм 303, 625
Сравнение строк 68, 360, 366, 758, 761 Формула Эйлера 652
Среднее значение 579 Формулы суммирования 71
Стек 101 Функция
Строка 42, 750 ◊ накопленных вероятностей (ФНВ) 211
◊ сравнение 68, 360, 366, 761 ◊ плотности вероятностей (ФПВ) 211
Строки 225 ◊ попарного сравнения элементов 144
Структура ◊ сравнения 145
◊ с реализацией очереди с приоритетами ◊ хеширования 214, 217
Фурье 565
146
◊ «поиск-объединение» (union-find) 291 Х
Структуры данных 95
Судоку 333 Хаусдорфово расстояние 739
Сумма Минковского 748 Хаффмана, код 768
Суффиксное дерево 507 Хемминга, расстояние 738
Суффиксный массив 509 Хеширование 123, 126, 131, 142, 214
Сходство фигур 737
Предметный указатель 847
Хеш-таблица 121, 131 Ш
Хеш-функция 121, 500
Хиршберга, алгоритм 764 Шарнир 638
Хроматический индекс 679 ◊ графа 264
Шифр
Ц ◊ AES 771
◊ DES 771
Целочисленное программирование 421 ◊ RSA 772
Цикл Эйлера 423 ◊ сдвиг Цезаря 771
Цифровая подпись 774 Штейнера, дерево 294, 685
Штрихкод 372
Ч
Э
Частично упорядоченное множество 613
Частотное распределение 139 Эвристики 30
Числа Эвристический алгоритм 27
◊ Кармайкла 227 ◊ А* 345
◊ Фибоначчи 353 ◊ приблизительного решения 118
Чрезвычайно параллельные (embarrassingly Эйлеров цикл 446, 634
Экземпляр задачи сортировки 25
parallel) задачи 194 Эксцентриситет вершины 625
Стивен С. Скиена
Алгоритмы.
Руководство по разработке
3-е издание
Перевод с английского
Группа подготовки издания:
Руководитель проекта Евгений Рыбаков
Зав. редакцией Людмила Гауль
Редактор Григорий Добин
Компьютерная верстка Ольги Сергиенко
Оформление обложки Зои Канторович
"БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул., 20.