
- •Конспект лекций по курсу
- •Абстрактные структуры данных
- •Определение
- •Базовые структуры данных
- •Очереди и стеки
- •Деревья
- •Внутренние структуры данных
- •Отображение абстрактных структур данных на внутренние
- •Строка-вектор
- •1. Функция сцепления двух строк
- •2. Функция поэлементного сравнения двух строк
- •3. Функция разбиения строки.
- •4. Функция нахождения подстроки в строке
- •Строка-список
- •1. Сцепление двух строк
- •2. Поэлементное сравнение двух строк
- •3. Разбиение строки на части
- •4. Функция нахождения подстроки в строке
- •Стек-вектор
- •Стек-список
- •Очереди
- •Очередь-вектор
- •Очередь-список
- •Деревья
- •Классификация таблиц
- •Способ работы с таблицей
- •Способ доступа к таблице
- •Просматриваемые таблицы
- •Статическая просматриваемая таблица-вектор
- •Динамическая просматриваемая таблица-вектор
- •Просматриваемая таблица-список
- •Упорядоченные таблицы
- •Упорядоченная таблица-вектор
- •Динамическая упорядоченная таблица – вектор
- •Упорядоченная таблица – двоичное дерево
- •Перемешанные таблицы
- •Открытое перемешивание
- •Перемешивание сцеплением
Статическая просматриваемая таблица-вектор
Такая таблица представляется одномерным массивом элементов, размер которого заранее известен:
const int M = 100; /* максимальный размер таблицы */
struct Item{
int key;
Type info;
}; /* структура элемента таблицы */
Item table[M];
Реализация алгоритма поиска элемента не вызывает затруднений и может быть такой:
int search(int k)
{
int i;
for(i = 0; i < M && table[i].key != k; i++)
;
return (i < M ? i : -1);
}
Динамическая просматриваемая таблица-вектор
Динамические таблицы разрешают выполнение операций включения новых элементов и удаления существующих. Это накладывает дополнительные требования на отображение таблицы.
Прежде всего, поскольку разрешена операция включения, нужно иметь информацию о наличии в таблице свободных позиций; кроме того, при наличии в таблице нескольких свободных позиций необходимо решить, в какую именно будет включаться новый элемент.
Наличие в таблице свободных элементов может повлиять на реализацию алгоритма поиска.
Для фиксации в таблице свободных и занятых элементов полезно реорганизовать элемент таблицы, включив в него дополнительное (служебное) поле 1/0 – поле занятости (рис. II–36): значение 1 в этом поле означает, что элемент занят, значение 0 – что элемент свободен.
-
1/0
ключ
информация
Рис. II–36
В исходном состоянии таблица пуста, и все элементы таблицы помечены как свободные. При включении нового элемента в таблицу нужно найти подходящий свободный элемент. Критерием для выбора может служить длина доступа L(т.е. количество элементов таблицы, которое необходимо просмотреть, прежде чем будет найдена свободная позиция; в какой-то степени длина доступа аналогична длине поиска). Можно обеспечитьL= 1, если все операции включения выполнять в конец таблицы и использовать специальную переменную (например,int n;), которая определяет первый свободный элемент в конце таблицы. В исходном состоянии n=0; каждая операция включения нового элемента увеличивает значениеn.
При удалении элемента в найденном элементе таблицы достаточно установить в 0 поле занятости; можно не модифицировать значения других полей таблицы. Не следует при удалении элемента из середины таблицы перемещать информацию из конца таблицы в освободившуюся позицию, так как это может привести к увеличению времени выполнения операции. Отсюда, при удалении элемента из таблицы переменная nне меняет свое значение.
Таким образом, если для таблицы выполняются в произвольном порядке операции включения и удаления, в некоторый момент времени состояние таблицы может иметь вид, приведенный на рис. II–37. Следовательно, при выполнении поиска элемента в таблице следует учитывать, свободен очередной элемент или занят.
-
1/0
ключ
информация
1
25
...
0
13
...
1
47
...
0
18
...
0
33
...
Рис. II–37
Для динамических таблиц, использующих указанные выше операции включения и удаления, с течением времени может возникнуть ситуация, когда в конце таблицы свободных позиций нет (т.е. n = M), в то время как в середине таблицы есть много элементов, помеченных как свободные. В таких ситуациях, прежде чем можно будет выполнить очередную операцию включения нового элемента в таблицу, следует ее реорганизовать, собрав все свободные элементы в конце таблицы и изменив текущий размер таблицы (n). Такая операция получила название "сборки мусора". В зависимости от того, насколько часто прикладная программа выполняет операции включения/удаления, может оказаться удобнее выполнить операцию "сборки мусора", зато потом все операции включения не будут требовать дополнительные накладные расходы. С другой стороны, можно включать новый элемент в первую найденную свободную позицию, исключив тем самым операцию "сборки мусора", но увеличив время выполнения операции включения.
Тексты функций для выполнения операций включения, удаления, поиска элементов в таблице и "сборки мусора" приводятся ниже и в файле tab1vec.cpp.В приведенных примерах используются две вспомогательные функции:delInfo()– удаление информации иdupl()– создание копии данных. Конкретная реализация этих функций зависит от типа информации, включаемой в таблицу (типType), и определяется разработчиком соответствующего приложения.
const int M = 20; /* Максимальный размер таблицы */
struct Item{
int busy; /* поле занятости */
int key; /* ключ */
Type info; /* информация */
};
Item table[M]; /* Объявление таблицы как внешней (вне функций) приводит к тому, что все элементы инициализируются нулем; поэтому можно не устанавливать явно значения 0 в полеbusyвсех элементов при создании таблицы */
int n = 0;
/* поиск элемента в таблице */
int search(int k)
{
int i;
for(i = 0; i < n; i++)
if(table[i].busy && table[i].key == k)
return i; /* элемент найден – он занят и имеет искомый ключ */
return -1; /* элемент не найден */
}
/* удаление элемента*/
int del(int k)
{
int l;
if((l = search(k)) < 0)
return -1; /* указанного элемента в таблице нет */
table[l].busy = 0; /* "удаление" элемента */
delInfo(table[I].info);
return 0;
}
/* "сборка мусора" */
int garbage()
{
int i, cur = n;
n = 0;
for(i = 0; i < cur; i++)
if(table[i].busy){ /* элемент занят */
if(i != n) /* элемент должен быть перемещен */
table[n] = table[i]; /* перемещение элемента */
n++;
}
return n == M ? -1 : 0; /* в таблице нет свободного места */
}
/* включение нового элемента в таблицу */
int insert(int k, Type in)
{
if(search(k) >= 0)
return -1; /* в таблице есть элемент с заданным ключом */
if(n == M) /* в конце таблицы нет свободной позиции */
if(garbage() < 0) /* "сборка мусора" */
return -2; /* в таблице нет свободной позиции */
/* включение нового элемента в таблицу */
table[n].busy = 1;
table[n].key = k;
table[n++].info = dupl(in);
return 0;
}