Опубликован: 05.01.2015 | Доступ: свободный | Студентов: 2178 / 0 | Длительность: 63:16:00
Лекция 12:

Таблицы символов и деревья бинарного поиска

Программа 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 . Найдите ответ эмпирически, аналитически или обоими методами.

Бактыгуль Асаинова
Бактыгуль Асаинова

Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат?

Александра Боброва
Александра Боброва

Я прошла все лекции на 100%.

Но в https://www.intuit.ru/intuituser/study/diplomas ничего нет.

Что делать? Как получить сертификат?