ЛАБОРАТОРНАЯ РАБОТА № 7
ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ
1. Динамические структуры данных
Если до начала работы с данными невозможно определить, сколько памяти потребуется для их хранения, память выделяется по мере необходимости отдельными блоками, связанными друг с другом с помощью указателей. Такой способ организации данных называется динамическими структурами данных, поскольку их размер изменяется во время выполнения программы.
Из динамических структур в программах чаще всего используются линейные списки, стеки, очереди и бинарные деревья.
Самый простой способ связать множество элементов – сделать так, чтобы каждый элемент содержал ссылку на следующий. Такой список называется однонаправленным (односвязным). Если добавить в каждый элемент вторую ссылку – на предыдущий элемент, получится двунаправленный список (двусвязный), если последний элемент связать указателем с первым, получится кольцевой список.
Типовая структура двунаправленного линейного списка может выглядеть так:
struct Node{
int d;
Node *next;
Node *prev;
};.
Каждый элемент списка содержит ключ, идентифицирующий этот элемент. Ключ обычно бывает либо целым числом, либо строкой и является частью поля данных. В качестве ключа в процессе работы со списком могут выступать разные части поля данных. Например, если создается линейный список из записей, содержащих фамилию, год рождения, стаж работы и пол, любая часть записи может выступать в качестве ключа: при упорядочивании списка по алфавиту ключом будет фамилия, а при поиске, к примеру, ветеранов труда ключом будет стаж. Ключи разных элементов списка могут совпадать.
Над списками можно выполнять следующие операции:
– начальное формирование списка (создание первого элемента);
– добавление элемента в конец списка;
– чтение элемента с заданным ключом;
– вставка элемента в заданное место списка (до или после элемента с заданным ключом);
– удаление элемента с заданным ключом;
– упорядочивание списка по ключу.
2. Пример работы с линейным списком
Задание
Составить программу, формирующую сведения об отправлении поездов.
Каждый поезд описывается с помощью структуры, содержащей следующие поля:
– номер поезда (ключ списка);
– пункт назначения;
– время отправления.
Данные хранятся в виде двунаправленного линейного списка.
Программа должна реализовывать следующие операции:
– формирование меню для выбора действия пользователем;
– ввод данных в список, отсортированный по ключу;
– вывод данных из списка в виде таблицы;
– поиск элемента в списке по различным критериям (номеру поезда, имени пункта назначения, времени отправления);
– удаление элемента из списка по заданному ключу.
Текст программы
#include <Windows.h>
#include <iostream>
#include <iomanip>
using namespace std;
//Структура для формирования списка
struct Train {
int train_num; //Номер поезда
char p_nazn[20]; //Имя пункта назначения
char v_otpr[10]; //Время отправления
Train* prev; //Указатель на предыдущий элемент
Train* next; //Указатель на последующий элемент
};
Train* pbeg; //Указатель на начало списка
Train* pend; //Указатель на конец списка
//Список функций программы
void menu(); //Функция прорисовки меню
//Функция формирования первого элемента списка
Train* first(int t_num, char* p_nazn, char* v_otpr);
//Функция вставки элемента в упорядоченный список
void add_sort(Train** pbeg, Train** pend, int t_num, char* p_nazn, char* v_otpr);
//Функция поиска элемента по ключу (номер поезда)
Train* find(Train* const pbeg, int t_num);
//Функция поиска элемента по имени пункта назначения
bool find_punkt(Train* const pbeg, char* p_nazn);
//Функция поиска элемента по времени отправления
bool find_time(Train* const pbeg, char* v_otpr);
//Функция удаления элемента из списка по заданному
// ключу
bool remove(Train** pbeg, Train** pend, int key);
void vvod(); //Функция ввода данных в список
void vivod(); //Функция вывода элементов списка
//на экран
void search(); //Функция поиска элементов в списке
void del(); //Функция удаления элемента
// из списка
void hline(); //Функция прорисовки
//горизонтальной линии
int main()
{
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
pbeg = 0; //Инициализация указателя на первый
//элемент списка
pend = 0; //Инициализация указателя на последний
//элемент списка
int num = 0; //Переменная для хранения номера
//выбранного пункта меню
//Цикл обработки действий пользователя
while (num != 5)
{
menu();
cin >> num;
switch (num) {
case 1: vvod(); break;
case 2: vivod(); break;
case 3: search(); break;
case 4: del(); break;
case 5: break;
default: cout << "Неверный вариант выбора";
}
}
return 0;
}
void menu()
{
cout << "\n МЕНЮ \n";
cout << "1. Ввод данных\n";
cout << "2. Вывод данных\n";
cout << "3. Поиск\n";
cout << "4. Удаление\n";
cout << "5. Выход\n";
cout << "\nВведите номер пункта меню для дальнейшей работы\n";
}
//Функция формирования первого элемента списка
Train* first(int t_num, char* p_nazn, char* v_otpr)
{
//Создание нового элемента
Train* pv = new Train;
//Заполнение полей данных
pv->train_num = t_num;
strcpy_s(pv->p_nazn, p_nazn);
strcpy_s(pv->v_otpr, v_otpr);
//Инициализация указателей на соседние
//элементы списка
pv->prev = 0;
pv->next = 0;
return pv;
}
void add_sort(Train** pbeg, Train** pend, int t_num, char* p_nazn, char* v_otpr)
{
//Создание нового элемента
Train* pv = new Train;
//Заполнение полей данных
pv->train_num = t_num;
strcpy_s(pv->p_nazn, p_nazn);
strcpy_s(pv->v_otpr, v_otpr);
Train* pt = *pbeg;
while (pt) { //Просмотр списка
if (t_num < pt->train_num)
{
pv->next = pt;
if (pt == *pbeg) //Вставка в начало
//списка
{
pv->prev = 0;
*pbeg = pv;
}
else //Вставка в середину
// списка
{
(pt->prev)->next = pv;
pv->prev = pt->prev;
}
pt->prev = pv;
return;
}
pt = pt->next;
}
pv->next = 0; //Вставка в конец списка
pv->prev = *pend;
(*pend)->next = pv;
*pend = pv;
}
//Функция поиска элемента по номеру поезда
Train* find(Train* const pbeg, int t_num)
{
Train* pv = pbeg;
while (pv)
{
if (pv->train_num == t_num)
break;
pv = pv->next;
}
return pv;
}
//Функция поиска элемента по имени пункта назначения
bool find_punkt(Train* const pbeg, char* p_nazn)
{
bool find = false;
Train* pv = pbeg;
while (pv) //Просмотр списка
{
if (strcmp(pv->p_nazn, p_nazn) == 0)
{
find = true;
//Вывод на экран найденного элемента
cout << setw(5) << pv->train_num << setw(20) << pv->p_nazn << setw(10) << pv->v_otpr;
}
pv = pv->next;
}
return find;
}
//Функция поиска элемента по времени отправления
bool find_time(Train* const pbeg, char* v_otpr)
{
bool find = false;
Train* pv = pbeg;
while (pv) //Просмотр списка
{
if (strcmp(pv->v_otpr, v_otpr) == 0)
{
find = true;
//Вывод на экран найденного элемента
cout << setw(5) << pv->train_num << setw(20) << pv->p_nazn << setw(10) << pv->v_otpr;
}
pv = pv->next;
}
return find;
}
//Функция удаления элемента из списка
bool remove(Train** pbeg, Train** pend, int key)
{
if (Train* pkey = find(*pbeg, key))
{
//Если удаляется первый элемент из списка
if (pkey == *pbeg)
{
*pbeg = (*pbeg)->next;
if (*pbeg) (*pbeg)->prev = 0;
}
else
//Если удаляется последний элемент из списка
if (pkey == *pend)
{
*pend = (*pend)->prev;
(*pend)->next = 0;
}
//Если удаляется элемент из середины списка
else
{
(pkey->prev)->next = pkey->next;
(pkey->next)->prev = pkey->prev;
}
delete pkey;
return true;
}
return false;
}
//Функция ввода данных
void vvod()
{
int n;
int t_num;
char p_nazn[20];
char v_otpr[10];
//Ввод количества добавляемых записей
cout << "Введите кол-во добавляемых записей в список = ";
cin >> n;
//Цикл для ввода полей структуры
for (int i = 0; i < n; i++)
{
cout << "\nВведите номер поезда\n";
cin >> t_num;
cout << "Введите имя пункта назначения\n";
while (cin.get() != '\n');
cin.getline(p_nazn, 20);
cout << "Введите время отправления\n";
cin.getline(v_otpr, 10);
//Если в списке есть элементы - добавляется новый
// элемент с сортировкой списка
if (pbeg)
add_sort(&pbeg, &pend, t_num, p_nazn, v_otpr);
//Если список пуст - формируется первый
//элемент списка
else
{
pbeg = first(t_num, p_nazn, v_otpr);
pend = pbeg;
}
}
}
//Функция вывода списка на экран в виде таблицы
void vivod()
{
if (pbeg) //Если список не пуст - вывод на экран
{
//Прорисовка шапки таблицы
cout << "\n Список поездов\n";
hline();
cout << "| Номер | Пункт назначения | Время отп. |\n";
hline();
//Вывод элементов списка на экран
Train* pv = pbeg;
while (pv)
{
cout << "| " << setw(5) << pv->train_num;
cout << " | " << setw(20) << pv->p_nazn;
cout << " | " << setw(10) << pv->v_otpr << " |" << endl;
pv = pv->next;
}
//Отчеркивание нижней гранцы таблицы
hline();
}
else //Если список пуст - вывод сообщения
cout << "\nСписок пуст!\n";
}
//Функция поиска элементов в списке
void search()
{
if (pbeg)
{
int k_poisk;
//Прорисовка меню выбора критерия поиска
cout << "\nВыберите критерий поиска\n";
cout << "1. Поиск по номеру поезда\n";
cout << "2. Поиск по имени пункта назначения\n";
cout << "3. Поиск по времени отправления\n";
cout << "\nВведите номер критерия ";
cin >> k_poisk;
//Обработка выбора критерия пользователем
switch (k_poisk)
{
case 1: //Поиск по номеру поезда
int t_num;
cout << "\nВведите номер поезда ";
cin >> t_num;
if (Train* pv = find(pbeg, t_num))
{
cout << "\nРезультат поиска:\n";
cout << setw(5) << pv->train_num << setw(20) << pv->p_nazn << setw(10) << pv->v_otpr;
}
else
cout << "Поезд с таким номером не найден\n";
break;
case 2: //Поиск по имени пункта назначения
char p_nazn[20];
cout << "\nВведите имя пункта назначения\n";
while (cin.get() != '\n');
cin.getline(p_nazn, 20);
cout << "\nРезультат поиска:\n";
if (!find_punkt(pbeg, p_nazn))
cout << "Поезда с таким пунктом назначения не найдены\n";
break;
case 3: //Поиск по времени отправления
char v_otpr[10];
cout << "\nВведите время отправления\n";
while (cin.get() != '\n');
cin.getline(v_otpr, 10);
cout << "\nРезультат поиска:\n";
if (!find_time(pbeg, v_otpr))
cout << "Поезда с таким временем отправления не найдены\n";
break;
default: cout << "Неверный вариант выбора\n";
}
}
else
cout << "\nСписок пуст!\n";
}
//Функция удаления элемента из списка
void del()
{
if (pbeg)
{
int t_num;
//Ввод номера поезда для поиска и удаления
//соответствующей записи
cout << "Введите номер поезда ";
cin >> t_num;
if (remove(&pbeg, &pend, t_num))
cout << "\nЗапись удалена\n";
else
cout << "\nЗапись с таким номером не найдена\n";
}
else
cout << "\nСписок пуст!\n";
}
//Функция для проведения горизонтальной линии
// в таблице
void hline()
{
const int m = 45;
for (int i = 0; i < m; i++)
cout << "-";
cout << endl;
}
3. Варианты работы
Создать программу, формирующую данные определенной структуры в виде двунаправленного линейного списка. Структура данных зависит от варианта.
Программа должна реализовывать следующие операции:
– формирование меню для выбора действия пользователем;
– ввод данных в список, отсортированный по ключу;
– вывод данных из списка в виде таблицы;
– поиск элемента в списке по различным критериям (номеру поезда, имени пункта назначения, времени отправления);
– удаление элемента из списка по заданному ключу.
1. Составить программу, которая обрабатывает информацию о наличии автобусов в автобусном парке.
Сведения о каждом автобусе содержат:
– номер автобуса (ключ);
– ФИО водителя;
– номер маршрута.
2. Составить программу, которая обрабатывает информацию о книгах в библиотеке.
Сведения о книгах содержат:
– номер УДК (ключ);
– ФИО автора;
– название;
– год издания.
3. Составить программу, которая обрабатывает информацию о заявках на авиабилеты.
Каждая заявка содержит:
– номер рейса (ключ);
– пункт назначения;
– ФИО пассажира;
– желаемую дату вылета.
4. Составить программу, формирующую телефонный справочник.
Сведения об абоненте содержат:
– номер телефона (ключ);
– ФИО абонента;
– адрес абонента.
5. Составить программу, которая обрабатывает информацию о наличии бензина на автозаправочной станции.
Сведения о бензине содержат:
– марка бензина (ключ);
– цена за литр;
– количество литров наличии.
6. Составить программу, которая обрабатывает информацию о врачах, работающих в поликлинике.
Сведения о враче содержат:
– табельный номер врача (ключ);
– ФИО врача;
– специализация;
– номер кабинета.
7. Составить программу, которая обрабатывает информацию о гражданах, лежащих в больнице.
Сведения о больном содержат:
– номер больного (ключ)
– ФИО больного;
– диагноз;
– номер палаты.
8. Составить программу, которая обрабатывает информацию для учета автомобильных грузоперевозок.
Сведения о грузовике содержат:
– номер грузовика (ключ);
– ФИО водителя;
– грузоподъемность.
9. Составить программу, которая обрабатывает информацию о наличии приборов на складе.
Сведения о приборе содержат:
– название прибора (ключ);
– тип прибора;
– цена;
– количество на складе.
10. Составить программу, которая обрабатывает информацию о заказах на ремонт вычислительной техники.
Сведения о заказе содержат:
– номер заказа (ключ);
– ФИО заказчика;
– описание неисправности;
– стоимость ремонта.
11. Составить программу, которая обрабатывает информацию о лабораториях института.
Сведения о лаборатории содержат:
– номер лаборатории (ключ);
– количество компьютеров;
– ФИО ответственного лаборанта.
12. Составить программу, которая обрабатывает информацию о мебельных гарнитурах, продаваемых в магазине.
Сведения о гарнитуре содержат:
– название гарнитура (ключ);
– количество предметов;
– цена;
– наличие на складе.
13. Составить программу, которая обрабатывает информацию о продаже автомобилей в автосалоне.
Сведения об автомобиле содержат:
– номер автомобиля (ключ);
– марка автомобиля;
– дата продажи;
– ФИО менеджера.
14. Составить программу, которая обрабатывает информацию о заказе на пошив одежды в ателье.
Сведения о заказе содержат:
– номер заказа (ключ);
– предмет одежды;
– ФИО закройщика;
– стоимость материала.
15. Составить программу, которая обрабатывает информацию о продаже билетов на концерт.
– дата концерта (ключ);
– название исполнителя;
– количество проданных билетов.
16. Составить программу, которая обрабатывает информацию о продаже путевок в туристическом агентстве.
Сведения о туре содержат:
– название тура (ключ);
– продолжительность тура;
– стоимость путевки;
– количество проданных путевок.
17. Составить программу, которая обрабатывает информацию о пользователях компьютерной сети.
Сведения о пользователе содержат:
– логин пользователя(ключ);
– дата регистрации;
– тип пользователя.
18. Составить программу, которая обрабатывает информацию о продажах компьютерных игр.
Сведения о туре содержат:
– название игры (ключ);
– издатель;
– количество проданных физических копий;
– количество проданных цифровых копий.
19. Составить программу, которая обрабатывает информацию о гостиничных номерах.
Сведения о номере содержат:
– номер комнаты (ключ);
– этаж;
– вид номера;
– количество мест.
20. Составить программу, которая обрабатывает информацию о таксопарке.
Сведения о такси содержат:
– номер машины (ключ);
– ФИО водителя;
– марка машины;
– стаж водителя.
21. Составить программу, которая обрабатывает информацию об авиаполке.
Сведения об авиаполке содержат:
– номер полка (ключ);
– ФИО командира;
– количество самолетов;
– количество боеготовых самолетов.
22. Составить программу, которая обрабатывает информацию об учебной дисциплине.
Сведения об учебной дисциплине содержат:
– шифр дисциплины (ключ);
– название дисциплины;
– количество лекционных часов;
– количество часов на лабораторные работы.
23. Составить программу, которая обрабатывает информацию о товарах.
Сведения о товарах содержат:
– индекс товара (ключ);
– название товара;
– цена товара.
24. Составить программу, которая обрабатывает информацию о счетах.
Сведения о счете содержат:
– номер счета (ключ);
– ФИО клиента;
– годовой процент.
25. Составить программу, которая обрабатывает информацию о сотрудниках.
Сведения о сотруднике содержат:
– табельный номер (ключ);
– ФИО сотрудника;
– должность.
26. Составить программу, которая обрабатывает информацию о студентах.
Сведения о студенте содержат:
– номер зачетки (ключ);
– ФИО студента;
– группа.
27. Составить программу, которая обрабатывает информацию о файлах.
Сведения о файле содержат:
– название файла (ключ);
– тип файла;
– размер файла.
28. Составить программу, которая обрабатывает информацию об оборудовании.
Сведения об оборудовании содержат:
– серийный номер (ключ);
– название оборудования;
– тип оборудования;
– стоимость оборудования.