
- •220300 - Системы автоматизированного проектирования
- •Тема 2. Технологии программирования
- •Тема 2. Технология разработки крупных приложений
- •Структуры
- •Структуры и функции
- •Массивы структур
- •Поиск в массиве структур
- •Вложенность структур
- •Рекурсия
- •Алгоритм быстрой сортировки
- •Массивы структур и бинарные файлы
- •Динамические структуры данных
- •Линейные списки
- •Очереди
- •Контрольная работа
- •Объектно-ориентированное программирование. Классы
- •Конструкторы
- •Перегруженные конструкторы
- •Определение методов класса вне класса
- •Объекты, возвращаемые функцией (методом)
- •Структуры и классы
- •Классы и память
- •Статические данные класса
- •Константные методы
- •Деструкторы
- •Массивы и классы
- •Массивы объектов
- •Строки Строковый тип или стандартный класс string
- •Тип строк AnsiString
- •Перегрузка операций
- •Перегрузка арифметических операций
- •Перегрузка операций сравнения
- •Перегрузка операции приведения типа
- •Преобразования объектов в основные типы и наоборот
- •Преобразование объектов классов в объекты других классов
- •Наследование
- •Конструкторы производного класса
- •Перегрузка функций
- •Иерархия классов
- •Общее и частное наследование. Комбинации доступа
- •Множественное наследование
- •Включение. Классы в классах
- •Виртуальные и дружественные функции
- •Абстрактные классы и чистые виртуальные функции
- •Виртуальные деструкторы
- •Виртуальные базовые классы или устранение неоднозначности при множественном наследовании
- •Дружественные функции
- •Дружественные классы
- •Указатель this
- •Многофайловые программы
- •Распознавание нажатых клавиш
Массивы структур и бинарные файлы
Рассмотрим пример формирования структурного массива на основе информации из двоичного файла. Предположим, что существует бинарный файл, в котором хранится информация о товарах. Рассмотрим пример, демонстрирующий считывание этой информации и формирование структурного динамического массива.
…
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
|
Итак, опишем структуру, зная, что каждый элемент стека должен содержать целое число и указатель на следующий элемент:
…
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