Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_С++_последная.doc
Скачиваний:
42
Добавлен:
07.05.2019
Размер:
876.54 Кб
Скачать

6.2. Динамические структуры данных

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

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

struct Node

{

int d;

Node *p;

};

В зависимости от решаемой задачи в программах применяются различные виды динамических структур.

6.2.1. Стек

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

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

struct Node // Элемент стека

{

int left. right;

Node* p;

};

Node* top = 01; // Вершина стека

Удобно оформить занесение и выборку элемента в виде отдельных функций. Функция помещения в стек обычно называется push, а выборки – pop. Все необходимое передается функциям через параметры, не будем использовать отдельную функцию для занесения первого элемента в стек, так как если указателю top присвоить 0 перед первым обращением к функции push( ), то функция push вполне прилично справится с созданием первого элемента стека:

Node* push(Node* top, const int l, const int r) // Занесение в стек

{

Node* pv = new Node; // 1

pv->left = l; // 2

pv->right = r; // 3

pv->p = top; // 4

return pv; // 5

}

Node* pop(Node* top, int& 1, int& r) // Выборка из стека

{

Node* pv = top->p; // 6

1 = top->1eft; // 7

r = top->right; // 8

delete top; // 9

return pv; // 10

}

Рассмотрим эти функции, самым тщательным образом вникая в детали. Чтобы занести в стек границы фрагмента, надо передать в функцию push() эти границы, а также указатель на вершину стека, в который мы собираемся их заносить. Перед границами указано ключевое слово const, чтобы подчеркнуть тот факт, что они не должны изменяться внутри функции.

Прежде всего мы описываем вспомогательную переменную-указатель и заносим в нее адрес нового элемента стека, который создается с помощью операции new (оператор 1). Выделяется столько памяти, сколько необходимо для хранения структуры типа Node. В операторах 2 и 3 информационные поля этой структуры 1eft и right заполняются значениями переданных в функцию границ фрагмента массива. Доступ к этим полям выполняется через указатель pv и операцию выбора ->. Новый элемент становится вершиной стека. Поле его указателя должно ссылаться на элемент, помещенный в стек ранее. Эта ссылка создается в операторе 4. Если «заталкиваемый» в стек элемент является первым, то в качестве первого аргумента функции push () надо задать 0.

Функция push возвращает указатель на вершину стека. Им всегда является указатель на только что занесенный элемент (оператор 5).

Выборка из стека (функция pop) выполняется аналогично. Сначала из вершины стека выбирается указатель на его следующий элемент (оператор 6), который станет новой вершиной стека. Этот указатель является возвращаемым значением функции (оператор 10). Информационная часть элемента заносится в переменные l и r, которые передаются в вызывающую функцию по ссылке (операторы 7 и 8). После того как вся информация из элемента выбрана, его можно удалить (оператор 9).

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