
ПР №5 Кольцевой односвязный список
.docФЕДЕРАЛЬНОЕ АГЕНТСТВО СВЯЗИ
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ
«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М.А. БОНЧ-БРУЕВИЧА»
(СПбГУТ)
Кафедра безопасности информационных систем
ОТЧЁТ
по итоговой работе №5 на тему: «Кольцевой односвязный список»
по дисциплине «Алгоритмы и структуры данных»
Выполнил: студент группы ИСТ-931, Гетманченко П.А.
«17» ноября 2020 г. ___________/П.А. Гетманченко /
Принял: к.ф.-м.н., доцент, Моисеев И. А.
«17» ноября 2020 г. __________/ И. А. Моисеев /
Основная часть
Цель работы: изучить понятие кольцевого односвязного списка, создав записную книжку на его основе.
Результаты выполнения работы
Шаг 1:
Первоначально нужно обязательно добавить к проекту файлы, а не просто открыть.
Результат:
List.cpp (файл с реализацией функций работы со списком)
#include "list.h"
int MainMenu()
{
system("cls");
cout << "Выберите действие" << endl;
cout << "1. Загрузка списка из файла" << endl;
cout << "2. Сохранение списка в файл" << endl;
cout << "3. Редактирование выбранной записи" << endl;
cout << "4. Добавление записи в список" << endl;
cout << "5. Удаление выбранной записи" << endl;
cout << "6. Поиск по списку" << endl;
cout << "7. Просмотреть весь список" << endl;
cout << "0. Выход" << endl;
int m = -1;
do {
cout << "> ";
cin >> m;
if (m < 0 || m > 7)
{
cout << "Некорректное значение, повторите ввод" << endl;
m = -1;
}
} while (m < 0);
return m;
}
int IndexMenu()
{
int d;
cout << "Введите номер записи: ";
cin >> d;
return d;
}
int FindMenu()
{
cout << "Выберите режим поиска" << endl;
cout << "1. по номеру записи" << endl;
cout << "2. по ФИО" << endl;
cout << "3. по году рождения" << endl;
cout << "4. по номеру телефона" << endl;
cout << "0. отмена" << endl;
int m = -1;
do {
cout << "> ";
cin >> m;
if (m < 0 || m > 4)
{
cout << "Некорректное значение, повторите ввод" << endl;
m = -1;
}
} while (m < 0);
return m;
}
Node* Load(Node* head, const char* fileName)
{
ifstream fin(fileName);
if (!fin.is_open())
{
cout << "ошибка открытия файла" << endl;
return head;
}
if (head != nullptr)
{
Clear(head);
head = nullptr;
}
Data val;
string str;
int index = 0;
while (!fin.eof())
{
// считываем из файла ФИО
getline(fin, str);
val.fullName = new char [str.size() + 1];
memset(val.fullName, 0, str.size() + 1);
memcpy_s(val.fullName, str.size() + 1, str.c_str(), str.size());
// считываем год рождения
fin >> val.year;
fin.get(); // забираем \n из конца строки
// считываем номер телефона
getline(fin, str);
val.phone = new char[str.size() + 1];
memset(val.phone, 0, str.size() + 1);
memcpy_s(val.phone, str.size() + 1, str.c_str(), str.size());
// добавляем элемент в список
if (!str.empty())
{
// вычисляем порядковый номер записи
val.index = ++index;
head = Insert(head, val);
}
}
fin.close();
cout << "Из файла прочитано " << index << " записей" << endl;
Show(head);
return head;
}
void Save(Node* head, const char* fileName)
{
if (head == nullptr)
{
cout << "Список пуст" << endl;
return;
}
ofstream fout(fileName);
if (!fout.is_open())
{
cout << "Ошибка открытия файла" << endl;
return;
}
Node* n = head;
int i = 0;
do
{
fout << n->value.fullName << endl;
fout << n->value.year << endl;
fout << n->value.phone << endl;
n = n->next;
i++;
} while (n != head);
fout.flush();
fout.close();
cout << "В файл записано " << i << " элементов списка" << endl;
}
Node* Insert(Node* head, Data val)
{
Node* newNode = new Node; // создаём новый узел списка
newNode->value = val; // запоминаем хранимое значение
if (head != nullptr) // если список не пуст
{
Node* n = head;
while (n->next != head) // находим последний узел списка
n = n->next;
n->next = newNode; // связываем последний узел с новым
}
else
head = newNode; // если список пуст, запоминаем новый узел как первый
newNode->next = head; // замыкаем список, последний элемент ссылается на первый
return head; // возвращаем указатель на первый элемент списка
}
void Edit(Node* head, int index)
{
if (head == nullptr)
{
cout << "Список пуст" << endl;
return;
}
Node* n = head;
while (n->next != head && n->value.index != index)
n = n->next;
if (n->value.index != index)
{
cout << "Элемент с заданным номером не найден" << endl;
return;
}
string str;
cout << "Введите ФИО (текущее значение: " << n->value.fullName << ")" << endl;
cin.ignore();
getline(cin, str);
delete[] n->value.fullName;
n->value.fullName = new char[str.size() + 1];
memset(n->value.fullName, 0, str.size() + 1);
memcpy_s(n->value.fullName, str.size() + 1, str.c_str(), str.size());
cout << "Введите год рождения (текущее значение: " << n->value.year << ")" << endl;
cin >> n->value.year;
cout << "Введите номер телефона (текущее значение: " << n->value.phone << ")" << endl;
cin.ignore();
getline(cin, str);
delete[] n->value.phone;
n->value.phone = new char[str.size() + 1];
memset(n->value.phone, 0, str.size() + 1);
memcpy_s(n->value.phone, str.size() + 1, str.c_str(), str.size());
cout << "Редактирование завершено" << endl;
}
Node* Add(Node* head)
{
Data val;
string str;
cout << "Добавление записи с список" << endl;
cout << "Введите ФИО: ";
cin.ignore();
getline(cin, str);
val.fullName = new char[str.size() + 1];
memset(val.fullName, 0, str.size() + 1);
memcpy_s(val.fullName, str.size() + 1, str.c_str(), str.size());
cout << "Введите год рождения: ";
cin >> val.year;
cout << "Введите номер телефона: ";
cin.ignore();
getline(cin, str);
val.phone = new char[str.size() + 1];
memset(val.phone, 0, str.size() + 1);
memcpy_s(val.phone, str.size() + 1, str.c_str(), str.size());
val.index = Size(head) + 1;
head = Insert(head, val);
cout << "Запись добавлена" << endl;
return head;
}
Node* Delete(Node* head, int index)
{
if (head == nullptr)
{
cout << "Список пуст" << endl;
return head;
}
Node* p = nullptr; // указатель на узел, предшествующий удаляемому
Node* n = head; // указатель на удаляемый узел
while (n->next != head && n->value.index != index)
{
p = n;
n = n->next;
}
if (n->value.index != index)
{
cout << "Элемент с заданным номером не найден" << endl;
return head;
}
// освобождаем память, занимаемую данными
delete[] n->value.fullName;
delete[] n->value.phone;
if (p == n) // если узел ссылается сам на себя, т.е. является единственным
{
delete n; // удаляем элемент
head = nullptr; // обнуляем указатель на начало списка
}
else if (n == head) // если удаляем не единственный, но первый элемент
{
head = head->next; // смещаем указатель на начало списка
p = head;
while (p->next != n) // ищем узел, предшествующий удаляемому
p = p->next;
}
p->next = n->next; // связываем элементы списка, исключая удаляемый
delete n; // удаляем узел
// корректируем номера оставшихся элементов списка
p = p->next;
do
{
p->value.index--;
p = p->next;
} while (p != head);
cout << "Запись удалена" << endl;
return head; // возвращаем указатель на начало списка
}
void Find(Node* head, int mode)
{
if (head == nullptr)
{
cout << "Список пуст" << endl;
return;
}
string str;
int x;
switch (mode)
{
case 1: //по номеру записи
cout << "Введите номер записи: ";
cin >> x;
break;
case 2: //по ФИО
cin.ignore();
cout << "Введите ФИО: ";
getline(cin, str);
break;
case 3: //по году рождения
cout << "Введите год рождения: ";
cin >> x;
break;
case 4: //по номеру телефона
cin.ignore();
cout << "Введите номер телефона: ";
getline(cin, str);
break;
default:
return;
}
cout << "Результаты поиска:" << endl;
Node* n = head;
int i = 0;
bool f;
do
{
switch (mode)
{
case 1: //по номеру записи
f = (x == n->value.index);
break;
case 2: //по ФИО
f = (strstr(n->value.fullName, str.c_str()) != nullptr);
break;
case 3: //по году рождения
f = (x == n->value.year);
break;
case 4: //по номеру телефона
f = (strstr(n->value.phone, str.c_str()) != nullptr);
break;
default:
break;
}
if (f == true)
{
cout << setw(2) << n->value.index << ") "
<< setw(20) << n->value.fullName << " "
<< n->value.year << "г.р., тел.: "
<< n->value.phone << endl;
i++;
}
n = n->next;
} while (n != head);
if (i == 0)
cout << "Ничего не найдено" << endl;
else
cout << "Найдено " << i << " записей" << endl;
}
void Show(Node* head)
{
if (head == nullptr)
{
cout << "Список пуст" << endl;
return;
}
Node* n = head;
do
{
cout << setw(2) << n->value.index << ") "
<< setw(20) << n->value.fullName << " "
<< n->value.year << "г.р., тел.: "
<< n->value.phone << endl;
n = n->next;
} while (n != head);
}
void Clear(Node* head)
{
Node* p = head;
Node* n = p->next;
Node* r = nullptr;
while (n != p)
{
r = n;
n = n->next;
// освобождаем память
delete[] r->value.fullName;
delete[] r->value.phone;
delete r;
}
// удаляем последний узел
delete[] n->value.fullName;
delete[] n->value.phone;
delete n;
}
int Size(Node* head)
{
if (head == nullptr)
return 0;
Node* n = head;
while (n->next != head)
n = n->next;
return n->value.index;
}
main.cpp (главный файл программы, где с функции main начинается выполнение программы)
#include "list.h"
#include <Windows.h>
int main()
{
setlocale(LC_ALL, "Russian");
SetConsoleOutputCP(1251);
SetConsoleCP(1251);
const char* fileName = "test.txt";
Node* head = nullptr;
int d = 0;
do {
d = MainMenu();
// Исполним выбранную команду
switch (d)
{
case 1: // Загрузка списка из файла
head = Load(head, fileName);
break;
case 2: // Сохранение списка в файл
Save(head, fileName);
break;
case 3: // Редактирование выбранной записи
Edit(head, IndexMenu());
break;
case 4: // Добавление записи в список
head = Add(head);
break;
case 5: // Удаление выбранной записи
head = Delete(head, IndexMenu());
break;
case 6: // Поиск по списку
Find(head, FindMenu());
break;
case 7: // Просмотреть весь список
Show(head);
break;
case 0: // Выход
Clear(head);
break;
}
system("pause");
} while (d != 0);
return 0;
}
List.h (заголовочный файл, с описанием всех функций работы со списком)
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
struct Data
{
int index; // порядковый номер записи
char* fullName; // фамилия и инициалы
int year; // год рождения
char* phone; // номер телефона
};
struct Node
{
Data value; // хранимое значение
Node* next; // указатель на следующий узел списка
};
int MainMenu(); // меню программы управления данными
int IndexMenu(); // меню ввода номера редактируемой или удаляемой записи
int FindMenu(); // меню выбора режима поиска
Node* Load(Node* head, const char *fileName); // загрузка файла данных с диска и вывод на экран
void Save(Node* head, const char* fileName); // запись файла на диск
Node* Insert(Node* head, Data val); // добавление записи в список
void Edit(Node* head, int index); // редактирование выбранной записи
Node* Add(Node* head); // добавление записи в список
Node* Delete(Node* head, int index); // удаление выбранной записи
void Find(Node* head, int mode); // поиск записи в файле
void Show(Node* head); // просмотр списка
void Clear(Node* head); // очистка памяти от списка
int Size(Node* head); // вычисление размера списка
Шаг 2:
Вид программы:
Шаг 3:
Действия программы:
Загрузка списка из файла
Сохранение списка из файла
Редактирование выбранной записи
Добавление записи в список
Удаление выбранной записи
Поиск по списку
По номеру записи:
По ФИО:
По году рождения:
По номеру телефона:
Отмена действия:
Просмотреть весь список
Выход
Выводы:
Была создана записная книжка на основе кольцевого односвязного списка с различными действиями, изменяющими информацию в ней.
Содержание
Основная часть 2
Результаты выполнения работы 2
Выводы 23
Содержание 23
САНКТ-ПЕТЕРБУРГ 2020