Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть 1.doc
Скачиваний:
63
Добавлен:
24.09.2019
Размер:
6.98 Mб
Скачать

5.1.2. Структуры для поддержки поиска

Структуры данных, поддерживающие поиск, хорошо проработаны и освещены в многочисленной литературе [7, 9, 3, 13]. Можно выделить три группы таких структур:

  • линейные (массивы и списки, возможно, предварительно отсортированные);

  • специальные виды деревьев, предназначенные для поддержки поиска;

  • хеш-таблицы (перемешанные таблицы) — структуры, предназначенные специально для поддержки эффективного поиска.

Каждая такая группа включает довольно большое количество конкретных структур, которые, однако, объединены общими принципами и, как правило, обеспечивают одинаковые асимптотические оценки сложности алгоритмов. Наиболее распространенные варианты для каждой из трех групп будут рассмотрены и проанализированы в данной главе. Изложение материала будет вестись именно в таком порядке — сначала линейные, затем древовидные структуры, в заключение — хеш-таблицы. Для каждой группы будут проанализированы оценки сложности.

Как обычно, основные алгоритмы доведены до работоспособных программных модулей. Для того, чтобы внести единообразие в реализацию различных структур данных, примем некоторые соглашения по программному интерфейсу, которые соответствуют принятой постановке задачи.

5.1.3. Соглашения по программному интерфейсу

Будем считать, что запись (структура каждого элемента item) состоит из двух полей key (ключ) и data (связанные данные), тип которых задается с помощью оператора typedef. В примерах для определенности предполагается, что ключ является положительным целым числом, а связанные данные имеют тип char. Разумеется, можно было бы определить шаблон элемента, чтобы иметь возможность быстро конструировать любые типы для конкретных случаев поиска, однако каждый такой случай, скорее всего, потребует внесения каких-то изменений и в алгоритмы. Поэтому программный код, который будет реализован ниже, следует рассматривать как основу для реальных приложений. Приведем определение структуры:

typedef int T_key; //тип ключа, может быть любым

typedef char T_data;//тип связанных данных, любой

struct item //структура элемента

{ T_key key; //ключ

T_data data; //связанные данные

};

Функции, которые будут реализованы при анализе различных структур для поддержки поиска, в качестве первого параметра принимают ссылку на структуру, в которой будет выполнен поиск. Эта ссылка для конкретных структур может иметь различный тип. Все остальные параметры и возвращаемые значения будут одинаковыми для всех случаев, так нам удобнее выполнять реализацию и сравнивать различные способы.

// функция поиска возвращает найденный элемент типа item

// параметр – искомое значение k типа T_key

item seach(<ссылка на структуру>, T_key k);

// функции вставки и удаления возвращают логическое значение,

// успешно или нет выполнены эти операции

bool insert(<ссылка на структуру>, item x);//x-вставляемый элемент

bool remove(<ссылка на структуру>, T_key k); // k-значение,

// которое нужно найти и удалить

Возможны и несколько иные варианты определения базовых функций, например, функции insert и remove могут иметь тип void, а неудачное выполнение операций обрабатываться как аварийная ситуация.

Функция поиска seach в данном определении возвращает целиком найденную запись (всегда единственную), если поиск успешен. Для случая промаха предусмотрим специальную константу nullitem («пустышка»). Если предположить, что ключами являются положительные целые числа (на практике такой случай является очень распространенным), то константу nullitem можно определить, например, так:

const item nullitem={-1};

После того, как соглашения по интерфейсу сделаны, перейдем к конкретным реализациям структур для поддержки поиска.