- •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
