Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат? |
Таблицы символов и деревья бинарного поиска
Программа 12.2. АТД таблицы символов
В данном интерфейсе определены операции для простой таблицы символов: инициализация, возврат значения счетчика элементов, поиск элемента с заданным ключом, добавление нового элемента, удаление элемента, выбор k-го наименьшего элемента и вывод элементов в порядке возрастания ключей (в указанный выходной поток).
template <class Item, class Key> class ST { private: // Код, зависящий от реализации public: ST(int); int count(); Item search(Key) ; void insert(Item); void remove(Item); Item select(int); void show(ostream&); };
Возможность присутствия элементов с одинаковыми ключами при реализации таблицы символов должна рассматриваться особо. Некоторые приложения не допускают повторения ключей, чтобы использовать их в качестве дескрипторов. Примером может служить использование табельных номеров работников в качестве ключей для их личных дел. Другие приложения могут включать много элементов с одинаковыми ключами: например, банку может потребоваться поиск в базе данных всех транзакций, касающихся конкретного клиента.
Обработку элементов с повторяющимися ключами можно выполнять различными способами. Один из подходов - потребовать, чтобы первичная структура данных поиска содержала только элементы с различными ключами и, для каждого ключа, ссылку на список элементов с такими же ключами. То есть в первичной структуре данных используются элементы, содержащие ключ и ссылку, а элементы с одинаковыми ключами отсутствуют. Для некоторых приложений эта организация удобна, поскольку все элементы с данным искомым ключом могут быть получены одной операцией найти или удалены одной операцией удалить. С точки зрения реализации такая организация эквивалентна поручению обработки повторяющихся ключей клиенту.
Вторая возможность - оставлять элементы с одинаковыми ключами в первичной структуре данных поиска и возвращать любой элемент в результате поиска по данному ключу. Такое соглашение проще для приложений, которые обрабатывают элементы по одному, а порядок обработки элементов с одинаковыми ключами не важен. Но с точки зрения разработки алгоритма это может оказаться неудобным, поскольку может потребовать включения в интерфейс механизма выборки всех элементов с данным ключом или вызова указанной функции для каждого элемента с заданным ключом.
Третья возможность - считать, что каждый элемент имеет уникальный идентификатор (кроме ключа) и потребовать, чтобы функция найти при заданном ключе отыскивала элемент с данным идентификатором. Или может потребоваться какой-либо более сложный механизм. Эти рассуждения применимы ко всем операциям с таблицами символов при наличии повторяющихся ключей. Нужно ли удалить все элементы с данным ключом, или любой элемент с этим ключом, или конкретный элемент (для этого потребуется реализация с дескрипторами элементов)? При описании реализаций таблиц символов мы будем неформально указывать способ обработки элементов с одинаковыми ключами, не обязательно рассматривая каждый механизм для каждой реализации.
Программа 12.3 - пример клиентской программы, который иллюстрирует некоторые из упомянутых выше соглашений для реализаций таблиц символов. Таблица символов используется в ней для поиска различных значений в последовательности ключей (сгенерированных случайным образом или считанных из стандартного ввода), которые затем выводятся в порядке возрастания.
Как обычно, следует иметь в виду, что различные реализации операций на таблицах символов имеют различные характеристики производительности, которые могут зависеть от конкретного набора операций. Одно приложение может использовать операцию вставить сравнительно редко (возможно, для построения таблицы), а затем выполнять очень большое количество операций найти; другое может выполнять в относительно небольших таблицах огромное количество операций вставить и удалить, вперемешку с операциями найти. Не в каждой реализации будут поддерживаться все операции, и некоторые из них могут обеспечивать эффективную поддержку определенных операций за счет других, неявно предполагая, что менее эффективные операции выполняются редко.
Программа 12.3. Пример клиента для таблицы символов
В этой программе таблица символов используется для поиска различных ключей в случайно сгенерированной или считанной из стандартного ввода последовательности. Для каждого ключа вызывается функция search - чтобы проверить, встречался ли такой ключ раньше. Если нет, элемент с этим ключом вставляется в таблицу символов. Типы ключей и элементов, а также абстрактные операции с ними определены в файле Item.cxx (см., например, программу 12.1).
#include <iostream.h> #include <stdlib.h> #include "Item.cxx" #include "ST.cxx" int main(int argc, char *argv[]) { int N, maxN = atoi(argv[1]), sw = atoi(argv[2]); ST<Item, Key> st(maxN); for (N = 0; N < maxN; N++) { Item v; if (sw) v.rand(); else if (!v.scan()) break; if (!(st.search(v.key())).null()) continue; st.insert(v); } st.show(cout); cout << endl; cout << N << " ключей" << endl; cout << st.count() << " различных ключей" << endl; }
Каждая из базовых операций в интерфейсе таблицы символов в каких-то случаях важна, поэтому для эффективного использования различных сочетаний операций предлагается множество базовых вариантов реализации. В этой и нескольких последующих главах основное внимание будет уделено реализациям базовых функций создать, вставить и найти, с некоторыми пояснениями, по мере необходимости, относительно функций удалить, выбрать, сортировать и объединить. Огромное множество рассматриваемых алгоритмов порождено различием характеристик производительности разных сочетаний базовых операций, и, возможно, ограничениями на значения ключей, размером элементов и другими факторами.
В этой главе мы встретимся с реализациями, в которых среднее время выполнения операций найти, вставить, удалить и выбрать для случайных ключей пропорционально логарифму количества элементов в словаре, а операция сортировать выполняется за линейное время. В "Сбалансированные деревья" мы рассмотрим способы достижения этого уровня производительности, и в разделе 12.2 будет приведена одна, а в "Хеширование" и "Поразрядный поиск" - несколько реализаций с постоянным временем выполнения.
Имеются и многие другие операции с таблицами символов. Примерами могут служить найти от метки, при котором поиск может начинаться с точки, в которой завершился предыдущий поиск; найти в диапазоне, когда нужно подсчитать или показать все узлы, попадающие в заданный интервал; и - при наличии концепции расстояния между ключами - поиск ближайшего соседа, при котором выполняется поиск ключей, ближайших к заданному. Такие операции будут рассматриваться в части VI, при изучении геометрических алгоритмов.
Упражнения
12.1. Напишите реализацию класса Item (аналогичную программе 12.1), который позволит в реализациях таблиц символов обрабатывать элементы, состоящие только из целочисленных ключей.
12.2. Напишите реализацию класса Item (аналогичную программе 12.1), который позволит в реализациях таблиц символов обрабатывать элементы, состоящие только из строковых ключей в стиле C. Класс должен содержать буфер для строк, как в программе 6.11.
12.3. Используя АТД таблицы символов из программы 12.2, реализуйте АТД стека и очереди.
12.4. Используя АТД таблицы символов из программы 12.2, реализуйте АТД очереди с приоритетами, который поддерживает операции удаления как максимального, так и минимального элементов.
12.5. Используя АТД таблицы символов из программы 12.2, реализуйте сортировку массива, совместимую с реализациями из глав 6-10.
12.6. Добавьте в программу 12.2 объявления деструктора, конструктора копирования и перегруженной операции присваивания, чтобы преобразовать ее в АТД первого класса (см. "Абстрактные типы данных" и 9.5).
12.7. Определите интерфейс АТД таблицы символов, позволяющий клиентским программам удалять заданные дескрипторами элементы и изменять ключи (см. "Абстрактные типы данных" и "Очереди с приоритетами и пирамидальная сортировка" ).
12.8. Приведите интерфейс и реализацию для элементов с двумя полями: 16-битным целочисленным ключом и строкой в стиле C, которая содержит информацию, связанную с этим ключом.
12.9. Укажите среднее количество различных ключей, которые найдет программа-драйвер (программа 12.3) среди N случайных положительных целых чисел, меньших 1000, для N = 10, 102, 103, 104 и 105 . Найдите ответ эмпирически, аналитически или обоими методами.