Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по Технологии разработки ПО 2005.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
833.54 Кб
Скачать

Массивы структур и бинарные файлы

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

ifstream fin(filename, ios::binary);

if(!fin) { cout << "\n Oshibka otkrytia faila!"; getch(); return 1; }

fin.seekg(0, ios::end); dfb = fin.tellg(); fin.seekg(0, ios::beg);

dlz=N+sizeof(int)+sizeof(float); //длина одной записи

KZ=dfb/dlz; //кол-во записей в файле

Tovar *ma = new Tovar [KZ];

fin.read(reinterpret_cast<char*>(ma), KZ*dlz);

fin.close();

cout << "\n Sodergimoe faila: " << endl;

for(i=0; i<KZ; i++) cout << ma[i].name << " " << ma[i].number << " " << ma[i].cena << endl;

Лекция 3 (5 стр.)

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

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

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

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

Элемент любой динамической структуры данных представляет собой структуру (struct), содержащую поля для хранения данных и для указателя.

struct Node {

int d;

Node *p;

};

Линейные списки

Самый простой способ связать множество элементов – сделать так, чтобы каждый элемент содержал ссылку на следующий. Такой список называется однонаправленным (односвязным). Если добавить в каждый элемент вторую ссылку на предыдущий элемент, получится двунаправленный список (двусвязный), если последний элемент связать указателем с первым, получится кольцевой список.

Пример структуры двунаправленного линейного списка:

struct DvSpisok {

int d;

Node *next; //указатель на следующий элемент

Node *pred; //указатель на предыдущий элемент

};

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

  • начальное формирование списка (создание первого элемента);

  • добавление элемента в конец списка;

  • чтение элемента с заданным ключом;

  • вставка элемента в заданное место списка (до или после элемента с заданным ключом);

  • удаление элемента с заданным ключом;

  • упорядочивание списка по ключу.

Сортировка связанного списка заключается в изменении связей между элементами. Алгоритм состоит в том, что исходный список просматривается, и каждый элемент вставляется в новый список на место, определяемое значением его ключа.

Стеки

Стеком называется структура данных, в которой элемент, занесённый первым, извлекается последним. Стек реализует принцип обслуживания LIFO (последним пришёл – первым ушёл). В алгоритме быстрой сортировки стек используется для хранения границ неупорядоченных фрагментов. Стек – это частный случай однонаправленного списка, добавление элементов в который и выборка из которого выполняются с одного конца, называемого вершиной стека. Другие операции со стеком не определены. При выборке элемент исключается из стека. Стеки широко применяются в системном ПО, компиляторах и в различных рекурсивных алгоритмах.

pop

push

Рассмотрим программу, которая формирует стек из пяти целых чисел (1, 2, 3, 4, 5) и выводит его на экран. Функция помещения в стек по традиции называется push, а выборки из стека - pop. Указатель top для работы со стеком всегда ссылается на его вершину.

Итак, опишем структуру, зная, что каждый элемент стека должен содержать целое число и указатель на следующий элемент:

struct Stack {

int d;

Stack *p;

};

//---------------------------Начальное формирование стека:

Stack* first(int d)

{

Stack *pv = new Stack; // Описываем вспомогательную переменную-указатель pv и заносим // в неё адрес нового элемента стека, который создаётся с помощью операции new.

pv->d = d; pv->p = 0; // занесение первого элемента в стек

return pv;

}

//---------------------------Занесение в стек:

void push(Stack **top, int d) // в функцию передаются элементы стека и указ. на вершину

{

Stack *pv = new Stack;

pv->d = d; //информационное поле структуры заполняется переданными в функцию значениями.

pv->p = *top; // новый элемент становится вершиной стека и поле его указателя ссылается

*top = pv; // на ранее помещённый в стек элемент.

}

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

//---------------------------Выборка из стека:

int pop(Stack **top)

{

int temp = (*top)->d;

Stack *pv = *top;

*top = (*top)->p;

delete pv; // удаление элемента

return temp;

}

//---------------------------Главная функция:

int main(int argc, char* argv[])

{

Stack *top = first(1); // занесение первого элемента в стек

for (int i = 2; i<6; i++) push(&top, i); // занесение в стек элементов, путём передачи этих элементов и указателя на вершину стека в функцию push.

while (top) cout << pop(&top) << " ";

return 0;

}

Результат работы программы: 5 4 3 2 1