Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СТА (лекции+лабы) / СТА Лекция 4.docx
Скачиваний:
49
Добавлен:
16.03.2016
Размер:
37.26 Кб
Скачать

Интерфейс отображений

Предположим, необходимо создать отображение, в котором и ключ, и значение являются целыми числами. Ниже представлен заголовочный файл с интерфейсом такого АТД:

#ifndef _INTEGER_MAP_HPP_

#define _INTEGER_MAP_HPP_

// Форвардное объявление структуры-отображения

struct IntegerMap;

// Создание нового объекта-отображения

IntegerMap * IntegerMapCreate ();

// Уничтожение объекта-отображения

void IntegerMapDestroy ( IntegerMap * _pMap );

// Очистка отображения

void IntegerMapClear ( IntegerMap & _map );

// Проверка отображения на пустоту

bool IntegerMapIsEmpty ( const IntegerMap & _map );

// Проверка отображения на содержание указанного ключа

bool IntegerMapHasKey ( const IntegerMap & _map, int _key );

// Поиск значения по указанному ключу в отображении

int IntegerMapFind ( const IntegerMap & _map, int _key );

// Вставка пары ключ-значение в отображение

void IntegerMapInsertKey ( IntegerMap & _map, int _key, int _value );

// Удаление элемента с указанным ключом из отображения

void IntegerMapRemoveKey ( IntegerMap & _map, int _key );

#endif // _INTEGER_MAP_HPP_

Можно представить простую тестовую программу, использующую отображения данного типа:

#include "integer_map.hpp"

#include <cassert>

int main ()

{

// Создаем объект-отображение

IntegerMap * pMap = IntegerMapCreate();

// Вставляем в отображение 3 пары ключ-значение

IntegerMapInsertKey( * pMap, 10, 100 );

IntegerMapInsertKey( * pMap, 20, 200 );

IntegerMapInsertKey( * pMap, 30, 300 );

// Проверяем корректность поиска в отображении

assert( IntegerMapFind( * pMap, 20 ) == 200 );

// Удаляем элемент по одному из ключей

IntegerMapRemoveKey( * pMap, 30 );

// Убеждаемся, что такого элемента больше нет в отображении

assert( ! IntegerMapHasKey( * pMap, 30 ) );

// Уничтожаем объект-отображение

IntegerMapDestroy( pMap );

}

Реализация отображений при помощи векторов

Самой простой, но не слишком эффективный, способ реализации отображений состоит в использовании векторов и простого алгоритма поиска ключей, основанного на полном переборе. Представляется возможным создать вектор, хранящий пары ключ-значение в виде несложной вложенной структуры:

struct IntegerPairVector

{

int m_nUsed;

int m_nAllocated;

struct Cell

{

int m_key;

int m_value;

};

Cell * m_pData;

};

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

Простое и элегантное решение, повторно использующее наработки из предыдущих лекций, можно построить задействовав отдельные вектора для ключей и значений. Если при вставке пар ключ-значение одновременно вносить данные в каждый из векторов, до в дальнейшем, при поиске значения по ключу, их позиции в обоих векторах совпадут. В случае удаления элемента ключ и значение также следует удалять из векторов одновременно, чтобы не нарушить порядок позиций всех остальных пар ключ-значение:

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

Ниже представлена реализация отображения, основанная на предложенной идее:

#include "integer_map.hpp"

#include "integer_vector.hpp"

#include <cassert>

// Структура для отображения из двух отдельных векторов для ключей и значений

struct IntegerMap

{

IntegerVector m_keys;

IntegerVector m_values;

};

// Создание объекта-отображения

IntegerMap * IntegerMapCreate ()

{

// Создаем объект-отображение в динамической памяти

IntegerMap * pMap = new IntegerMap;

// Инициализируем оба внутренних вектора

IntegerVectorInit( pMap->m_keys );

IntegerVectorInit( pMap->m_values );

// Возвращаем объект во внешний код

return pMap;

}

// Уничтожение объекта-отображения

void IntegerMapDestroy ( IntegerMap * _pMap )

{

// Освобождаем ресурсы внутренних векторов

IntegerVectorDestroy( _pMap->m_keys );

IntegerVectorDestroy( _pMap->m_values );

// Удаляем сам объект-отображение

delete _pMap;

}

// Очистка отображения

void IntegerMapClear ( IntegerMap & _map )

{

// Очищаем оба внутренних вектора

IntegerVectorClear( _map.m_keys );

IntegerVectorClear( _map.m_values );

}

// Проверка отображения на пустоту

bool IntegerMapIsEmpty ( const IntegerMap & _map )

{

// Отображение пусто, если пусты внутренние векторы.

// Поскольку векторы модифицируются всегда одновременно,

// достаточно проверить один из векторов на пустоту, например, вектор ключей

return IntegerVectorIsEmpty( _map.m_keys );

}

// Вспомогательная функция для поиска позиции ключа в отображении

int IntegerMapFindKeyPosition ( const IntegerMap & _map, int _key )

{

// Ищем позицию ключа в векторе ключей путем полного перебора

for ( int i = 0; i < _map.m_keys.m_nUsed; i++ )

if ( _map.m_keys.m_pData[ i ] == _key )

// Позиция найдена

return i;

// Позиция не найдена

return -1;

}

// Проверка отображения на содержание указанного ключа

bool IntegerMapHasKey ( const IntegerMap & _map, int _key )

{

// Ключ есть в отображении, если поиск его позиции дает корректный ответ

return IntegerMapFindKeyPosition( _map, _key ) != -1;

}

// Поиск значения по указанному ключу в отображении

int IntegerMapFind ( const IntegerMap & _map, int _key )

{

// Ищем позицию ключа в векторе ключей

int position = IntegerMapFindKeyPosition( _map, _key );

// Ключ должен существовать!

assert( position != -1 );

// Используем найденную позицию для извлечения значения из вектора значений

return _map.m_values.m_pData[ position ];

}

// Вставка пары ключ-значение в отображение

void IntegerMapInsertKey ( IntegerMap & _map, int _key, int _value )

{

// Ищем позицию ключа в векторе ключей. Возможно такой ключ уже существует

int position = IntegerMapFindKeyPosition( _map, _key );

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

if ( position == - 1 )

{

IntegerVectorPushBack( _map.m_keys, _key );

IntegerVectorPushBack( _map.m_values, _value );

}

else

// В противном случае обновляем значение по существующему ключу

_map.m_values.m_pData[ position ] = _value;

}

// Удаление элемента с указанным ключом из отображения

void IntegerMapRemoveKey ( IntegerMap & _map, int _key )

{

// Ищем позицию ключа в векторе ключей

int position = IntegerMapFindKeyPosition( _map, _key );

// Ключ должен существовать!

assert( position != -1 );

// Одновременно удаляем ключ и значение из векторов в найденной позиции

IntegerVectorDeleteAt( _map.m_keys, position );

IntegerVectorDeleteAt( _map.m_values, position );

}

Соседние файлы в папке СТА (лекции+лабы)