Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lab1 / student

.cpp
Скачиваний:
1
Добавлен:
18.02.2023
Размер:
9.64 Кб
Скачать
//-- В задании необходимо разработать программу, в которой выполняется ввод списка записей определенного типа.
//-- Записи вводятся построчно в определенном формате, признак завершения ввода – ввод пустой строки. 
//-- Список – двунаправленный. При написании программы реализовать функции: 
//--добавление элемента в конец списка,
//вставка элемента перед текущим элементом списка,
//--удаление элемента из списка. 
//-- При вводе данных записи упорядочиваются по определенному полю (согласно варианту задания). 
//-- Направление упорядочивания на выбор разработчика.
//-- Полученный список вывести на экран.

// Фамилия, имя, отчество (строки по 15 символов); 
// номер зачетной книжки (целое шестизначное число);
// дата рождения (в формате дд.мм.гггг).
// Формат ввода: Фамилия Имя Отчество [No зачетной книжки], Дата рождения

/*
Сидоров Сидр Сидрович [131955], 14.07.1993
Иванов Иван Иванович [453465], 01.02.1996
Петров Петр Петрович [156556], 22.12.1998
Лапин Гавриил Васильевич [793907], 24.01.1980
Соболев Геннадий Леонидович [531426], 11.02.1983
Фомичев Владислав Николаевич [567018], 15.02.1983
Горшков Даниил Тимурович [686569], 18.04.1985
Доронин Богдан Семенович [151241], 17.07.1989
Анисимов Леонид Николаевич [105593], 11.11.1992
Лихачев Юрий Витальевич [420839], 09.10.1997
Вставка Перед Элементом [777777], 07.07.1997
*/

#include <iostream>
#include <sstream>
#include <string>
#include <regex>
#include <iomanip>
#include <Windows.h>
using namespace std;

#if defined(max)
#undef max
#endif

struct Student
{
	string lastname;
	string firstname;
	string middlename;
	int number = 0;
	string date;
	Student* next = nullptr;
	Student* prev = nullptr;
};

template <typename T>
bool get_value(stringstream& ss, T& value);
Student* push(string lastname, string firstname, string middlename, int number, string date, Student* last);
Student* insert(string lastname, string firstname, string middlename, int number, string date, Student* stk);
Student* pop(Student* stk);
void output(Student* stk);
string useless_symbol(string str);
Student* student_sort(Student* first);

int main()
{
	SetConsoleCP(1251);
	SetConsoleOutputCP(1251);

	Student* first = nullptr;
	Student* last = nullptr;
	
	string str;
	regex rg_format("[А-Я]{1}[а-я]{1,14} [А-Я]{1}[а-я]{1,14} [А-Я]{1}[а-я]{1,14} \\[[1-9]{1}[0-9]{5}\\], "
					"(0[1-9]|[12][0-9]|3[01]).(0[1-9]|1[012]).(19|20)[0-9]{2}");//регулярное выражение для проверки ввода

	cout << "Вводите данные студентов в формате 'Фамилия Имя Отчество [№ зачетной книжки], Дата рождения':" << endl;
	cout << "По завершении ввода введите пустую строку." << endl;
	
	while (1)
	{		
		getline(cin, str);//читаем строку из потока ввода
		if (str.empty()) break;//если строка пустая завершаем ввод
		if (!regex_match(str, rg_format))
		{
			cout << "Введенная строка не соответствует формату!" << endl;
			continue;
		}
		str = useless_symbol(str);//очищает строку от всех символов кроме букв, цифр и пробелов

		stringstream ss(str);//записываем строку в поток
		string lastname;
		string firstname;
		string middlename;
		int number;
		string date;
		if (get_value(ss, lastname) &&
			get_value(ss, firstname) &&
			get_value(ss, middlename) &&
			get_value(ss, number) &&
			get_value(ss, date))//если данные прочитаны успешно
		{
			last = push(lastname, firstname, middlename, number, date, last);
			if (first == nullptr) first = last;//если указатель на первый элемент не задан - задаем
		}
	}

	str.clear();
	cout << "Введите дату (студенты, родившиеся позже указанной даты, будут удалены):" << endl;
	tm t = {};
	cin >> get_time(&t, "%d.%m.%Y");
	while (cin.fail())
	{
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "Некорректный ввод! Попробуйте снова: ";
		cin >> get_time(&t, "%d.%m.%Y");
	}
	cin.ignore(numeric_limits<streamsize>::max(), '\n');

	Student* stk = first;
	while (stk != nullptr)//удаляем из списка студентов с датой позже указаной
	{
		tm d = {};
		istringstream ss(stk->date);
		ss >> get_time(&d, "%d.%m.%Y");
		if (!ss.fail() && mktime(&d) > mktime(&t))
		{
			if (first == stk) first = first->next;
			if (last == stk) last = last->prev;
			stk = pop(stk);
		}
		else stk = stk->next;
	}

	first = student_sort(first);//сортируем список
	output(first);//выводим результат
	system("pause");
	return 0;
}

template <typename T>
bool get_value(stringstream& ss, T& value)
{//ввод значений
	ss >> value;
	if (ss.fail())
	{
		ss.clear();
		ss.ignore(1, '\n');
		cout << "Некорректный ввод! Попробуйте снова: ";
		return false;
	}
	return true;
}

Student* push(string lastname, string firstname, string middlename, int number, string date, Student* last)
{//добавление элемента в конец списка
	Student* item = new Student;
	item->lastname = lastname;
	item->firstname = firstname;
	item->middlename = middlename;
	item->number = number;
	item->date = date;
	item->next = nullptr;
	item->prev = last;
	if (last != nullptr) last->next = item;
	return item;
}

Student* insert(string lastname, string firstname, string middlename, int number, string date, Student* stk)
{//вставка элмента в указанное место
	Student* item = new Student;
	item->lastname = lastname;
	item->firstname = firstname;
	item->middlename = middlename;
	item->number = number;
	item->date = date;
	item->next = stk;
	item->prev = stk->prev;
	if (stk->prev != nullptr) (stk->prev)->next = item;
	stk->prev = item;
	return item;
}

Student* pop(Student* stk)
{//удаление элемента
	if (stk == nullptr) return nullptr;
	Student* next = stk->next;
	Student* prev = stk->prev;
	if (next != nullptr) next->prev = prev;
	if (prev != nullptr) prev->next = next;
	delete stk;//удалили элемент
	return next;
}

void output(Student* stk)
{//вывод списка
	if (stk == nullptr) cout << "Список пуст!";
	while (stk != nullptr)
	{
		cout << stk->lastname << " " << stk->firstname << " " << stk->middlename << " " << stk->number << " " << stk->date << endl;
		stk = stk->next;
	}
	cout << endl;
}

string useless_symbol(string str)
{//удаление всех символов из строки кроме 'А-я', '0-9', ' ', '.' 
	int i = 0;
	while (str[i])
	{
		if ((str[i] < 'А' || str[i] > 'Я') &&
			(str[i] < 'а' || str[i] > 'я') &&
			(str[i] < '0' || str[i] > '9') &&
			str[i] != ' ' && str[i] != '.')
				str.erase(i, 1);
		else i++;
	}
	return str;
}

Student* student_sort(Student* first)
{//сортировка списка
	if (first == nullptr || first->next == nullptr) return first;
	
	Student* i = first;
	while (i != nullptr)
	{
		string min_str = i->lastname + i->firstname + i->middlename;
		Student* min_value = i;
		Student* j = i->next;
		while (j != nullptr)
		{
			string cur_str = j->lastname + j->firstname + j->middlename;
			if (cur_str < min_str)
			{
				min_str = cur_str;
				min_value = j;
			}

			j = j->next;
		}
		if (min_value != i)
		{
			Student* flip_next = i->next;
			Student* flip_prev = i->prev;

			if (i->next == min_value)
			{//если у текущего элемента следующий тот, с кем обмен (соседи)
				flip_next = i;
				min_value->prev = min_value;
			}
			
			i->next = min_value->next;
			i->prev = min_value->prev;
			if (i->next != nullptr) (i->next)->prev = i;
			if (i->prev != nullptr) (i->prev)->next = i;
			//если предыдущий элемент существует, то устанавливаем значение указателя next у предыдущего элемента на текущий

			min_value->next = flip_next;
			min_value->prev = flip_prev;
			if (min_value->next != nullptr) (min_value->next)->prev = min_value;
			if (min_value->prev != nullptr) (min_value->prev)->next = min_value;
			
			if (min_value->prev == nullptr) first = min_value;
		}
		i = min_value->next;
	}
	return first;
}