
- •Конспект лекций по курсу Программирование на языке высокого уровня.
- •Часть I. Структурное программирование
- •Автор: доцент Шустова л.И.
- •Часть II. Структуры данных 16
- •Часть III. Методы сортировки 97
- •Понятие системы программирования
- •Типы и назначение файлов
- •Директива#include
- •Директива #define
- •Директива условной генерации
- •Основы ввода/вывода
- •Вывод данных
- •Ввод данных
- •Определение и использование функций
- •Функция вычисления факториала числа.
- •Функция возведения вещественного числа в целую степень
- •Функция, меняющая местами значения двух параметров
- •Описание массива
- •Пример программы с использованием массива целых чисел
- •Абстрактные структуры данных
- •Определение
- •Базовые структуры данных
- •Очереди и стеки
- •Деревья
- •Внутренние структуры данных
- •Векторы
- •Отображение абстрактных структур данных на внутренние
- •Строка-вектор
- •1. Функция сцепления двух строк.
- •2. Функция поэлементного сравнения двух строк.
- •3. Функция разбиения строки.
- •4. Функция нахождения подстроки в строке.
- •Строка-список
- •1. Сцепление двух строк.
- •2. Поэлементное сравнение двух строк.
- •3. Разбиение строки на несколько частей.
- •4. Функция нахождения подстроки в строке.
- •Стек-вектор
- •Стек-список
- •Очереди
- •Очередь-вектор
- •Очередь-список
- •Деревья
- •Классификация таблиц
- •Способ работы с таблицей
- •Способ доступа к таблице
- •Просматриваемые таблицы
- •Просматриваемая таблица-вектор
- •Статическая просматриваемая таблица-вектор
- •Динамическая просматриваемая таблица-вектор
- •Просматриваемая таблица-список
- •Упорядоченные таблицы
- •Упорядоченная таблица-вектор
- •Динамическая упорядоченная таблица-вектор
- •Перемешанные таблицы
- •Открытое перемешивание
- •Перемешивание сцеплением
- •Деревья поиска
- •Бинарное дерево
- •Многоходовые деревья
- •Структура вершины в-дерева
- •Операция вставки
- •Удаление элемента
- •Перераспределение элементов
- •Сцепление вершин
- •Операция включения
- •Удаление элемента
- •Методы сортировки
- •Введение
- •Классификация методов внутренней сортировки
- •Быстрая сортировка
- •Распределительные сортировки
- •Сортировка поразрядным группированием
- •Сортировка вычислением адреса
Просматриваемая таблица-вектор
Определим элемент таблицы с помощью следующей структуры:
struct Item{
int key;
Type info;
};
Просматриваемая таблица представляется одномерным массивом элементов, размер которого заранее известен:
const int M = 100; /* максимальный размер таблицы */
Память под такую таблицу может быть выделена и статически, и динамически:
Item table[M]; // статическое выделение памяти
Item *table = new Item[M]; // динамическое выделение памяти
Реализация алгоритмов работы с таблицей, представлено вектором, не зависит от способа выделения памяти.
Статическая просматриваемая таблица-вектор
Для статической просматриваемой таблицы определена только операция поиска элемента. Реализация алгоритма поиска элемента не вызывает затруднений и может быть такой:
int search(int k)
{
int i;
for(i = 0; i < M && table[i].key != k; i++)
;
return (i < M ? i : -1);
}
Динамическая просматриваемая таблица-вектор
Динамические таблицы разрешают выполнение операций включения новых элементов и удаления существующих. Это накладывает дополнительные требования на отображение таблицы.
Прежде всего, поскольку разрешена операция включения, нужно иметь информацию о наличии в таблице свободных позиций; кроме того, при наличии в таблице нескольких свободных позиций необходимо решить, в какую именно будет включаться новый элемент. Свободные позиции в такой таблице могут появляться, в том числе, и в результате выполнения операций удаления элементов. Наличие в таблице свободных элементов может повлиять на реализацию всех операций с таблицей, в том числе, и на реализацию алгоритма поиска.
Рассмотрим различные способы реализации операций с таблицей.
Способ 1. Для фиксации в таблице свободных и занятых элементов полезно реорганизовать элемент таблицы, включив в него дополнительное (служебное) поле 1/0 – поле занятости (рис. II-35): значение 1 в этом поле означает, что элемент занят, значение 0 – что элемент свободен.
-
1/0
ключ
информация
Рис. II‑35.
В исходном состоянии таблица пуста, и все элементы таблицы помечены как свободные. При включении нового элемента в таблицу нужно найти подходящий свободный элемент. Критерием для выбора может служить длина доступа L(количество элементов таблицы, которое необходимо просмотреть, прежде чем будет найдена свободная позиция; в какой-то степени длина доступа аналогична длине поиска). Можно обеспечитьL= 1, если все операции включения выполнять в конец таблицы и использовать специальную переменную (например,int n;), которая определяет первый свободный элемент в конце таблицы. В исходном состоянии n=0; каждая операция включения нового элемента увеличивает значениеn. Если при выполнении операции включения в таблицу нового элемента свободная позиция не будет найдена, операция завершается отказом.
Пусть, например, выполнялись подряд несколько операций включения элементов в таблицу (последовательность элементов 25, 13, 47, 18, 33)
При удалении элементав найденном элементе таблицы достаточно установить в 0 поле занятости; можно не модифицировать значения других полей таблицы. Пусть, например, элементы удалялись в следующем порядке: 33, 18, 13.
Таким образом, после выполнения указанных выше операций включения и удаления, состояние таблицы может иметь вид, приведенный на рис. II-36. Если после этих операций будет выполняться, например, операция поиска элемента с ключом 13, она должна завершиться отказом (элемент был удален). Следовательно, при выполнении поиска элемента в таблице следует учитывать, свободен очередной элемент или занят.
-
1/0
ключ
информация
1
25
...
0
13
...
1
47
...
0
18
...
0
33
...
Рис. II‑36.
Такая реализация операции удаления влияет также и на операцию включения в таблицу нового элемента. Если новый элемент включается всегда в конец таблицы, с течением времени может возникнуть ситуация, когда в конце таблицы свободных позиций нет (т.е. n = M), в то время как в середине таблицы есть много элементов, помеченных как свободные. В таких ситуациях, прежде чем можно будет выполнить очередную операцию включения нового элемента в таблицу, следует ее реорганизовать, собрав все свободные элементы в конце таблицы и изменив текущий размер таблицы (n). Такая операция получила название "сборки мусора".
Поскольку операция сборки мусора приводит к перемещению информации в таблице, она является достаточно медленной. Данную операцию можно выполнять, например, вместе с операцией включения нового элемента в таблицу: если оказалось, что в конце таблицы нет свободного элемента, тогда выполняется операция сборки мусора. Если и после выполнения данной операции в конце таблицы нет свободного элемента, значит, таблица полна, и операция включения нового элемента завершается отказом.
Можно отказаться от выполнения операции сборки мусора, если новый элемент включать не просто в конец таблицы, а в первую свободную позицию в таблице. В этом случае при включении в таблицу нового элемента отыскивается позиция в таблице, помеченная как свободная, и в эту позицию заносится новый элемент. Кроме того, если найденная свободная позиция находится в конце таблицы, изменяется текущий размер таблицы (значение переменной nувеличивается). Если свободная позиция не будет найдена, значит, таблица полна, и операция включения завершается отказом.
Способ 2. Поле занятости не используется и не включается в структуру элемента таблицы. В этом случае алгоритм поиска реализуется без каких-либо изменений. Включение нового элемента выполняется всегда в конец таблицы, что приводит к увеличению значения n. При удалении элемента из таблицы в освободившуюся позицию переписывается последний элемент таблицы, после чего значение переменнойnуменьшается.
Выбор конкретного способа удаления зависит от многих причин, в том числе, от размера таблицы, частоты выполнения операций включения и удаления элементов и других. Нельзя утверждать, что какой-то способ из рассмотренных выше лучше, а какой-то хуже. Но в любом случае не следует при удалении элемента из середины таблицы перемещать информацию из нижней половины таблицы на одну позицию вверх, сохраняя исходный порядок включения элементов в таблицу. В просматриваемой таблице порядок размещения элементов никакого значения не имеет, тогда как подобная реализация операции удаления может привести к существенному увеличению времени выполнения операции.
Тексты функций для выполнения операций включения, удаления, поиска элементов в таблице и "сборки мусора" приводятся ниже и в файле Programs/tab1vec.cpp.
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; /* "удаление" элемента */
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 = in;
return 0;
}