Добавил:
CanyonE
СПбГУТ * ИКСС * Программная инженерия
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Решения лабораторных работ (местами есть ошибки) / Lab5_2_Queue (singly linked list)
.cpp#include <iostream>
#include <stdexcept>
using std::cin;
using std::cout;
using std::endl;
// Очередь на основе однонаправленного списка
template <class T>
class Queue {
protected:
struct queue { // Структура "Queue"
size_t n;
T *elem;
queue *child;
};
private:
queue *front_elem_ = nullptr; // Первый элемент очереди
queue *back_elem_ = nullptr; // Последний элемент очереди
public:
// Конструктор
Queue() = default;
// Конструктор копирования
Queue(const Queue &arg) {
if (arg.front_elem_) { // Если первый элемент очереди имеется
queue *t = arg.front_elem_; // Заносим указатель на него в t
for (size_t i = 0; i < arg.back_elem_->n; ++i) {
push(*t->elem), t = t->child; // Добавляем очередной элемент и перемещаем t внутрь
}
}
}
// Оператор копирования
Queue &operator=(const Queue &arg) {
Queue temp(arg);
swap(*this, temp);
return *this;
}
// Конструктор перемещения
Queue(Queue &&arg) noexcept {
front_elem_ = arg.front_elem_;
back_elem_ = arg.back_elem_;
arg.back_elem_ = arg.front_elem_ = nullptr;
}
// Оператор перемещения
Queue &operator=(Queue &&arg) noexcept {
if (this != &arg) {
swap(*this, arg); // Меняем значения
arg.clear(); // Освобождаем то, что раньше лежало в this
}
return *this;
}
// Деструктор
virtual ~Queue() {
clear();
}
// Удаление всех элементов из очереди
void clear() {
if (front_elem_) { // Если очередь в this была, то освобождаем её
queue *child = front_elem_->child; // Идем внутрь
while (child) { // Пока можно идти внутрь (child != nullptr), идем
delete child->elem; // Освобождаем память поля elem очередного элемента child
queue *next = child->child; // next передвигается внутрь child-родителя
delete child; // Освобождаем child-родителя
child = next; // Переуказываем child на next (на ребенка только что освобожденного родителя)
}
delete front_elem_; // Освобождаем самый первый элемент
front_elem_ = back_elem_ = nullptr; // Очищаем указатели
}
}
// Вставляет элемент в конец
Queue &push(const T &elem) {
if (front_elem_) { // Если очередь в this была
queue *t = back_elem_; // Получаем в t адрес, на который указывает back_elem_
back_elem_ = new queue {back_elem_->n + 1, new T {elem}, nullptr}; // Создаем новый back_elem_
t->child = back_elem_; // Переходим внутрь и перенаправляем на новый back_elem_
return *this;
}
back_elem_ = front_elem_ =
new queue {1, new T {elem}, nullptr}; // Если не было очереди, то создается первый элемент
return *this;
}
// Доступ к первому элементу
T &front() const noexcept(false) {
if (front_elem_) {
return *front_elem_->elem;
}
throw std::out_of_range("Queue. Method front. Out of range");
}
// Доступ к последнему элементу
T &back() const noexcept(false) {
if (back_elem_) {
return *back_elem_->elem;
}
throw std::out_of_range("Queue. Method back. Out of range");
}
// Удаляет первый элемент
void pop() noexcept(false) {
if (front_elem_) { // Если первый элемент имеется
delete front_elem_->elem; // Освобождаем его соответствующее поле
queue *child = front_elem_->child; // Переходим к след. элементу (номер 2)
delete front_elem_; // Освобождаем первый элемент
if (front_elem_ != back_elem_) { // Если размер очереди был != 1
front_elem_ = child; // Второй элемент становится первым
for (size_t i = 1; i < back_elem_->n; ++i) {
child->n = i, child = child->child; // Меняем значения поля N для всех child
}
return;
}
back_elem_ = front_elem_ = nullptr; // Если размер очереди был = 1, то обнуление
return;
}
throw std::out_of_range("Queue. Method pop. Out of range");
}
// Возвращает размер очереди
size_t size() const {
if (back_elem_) {
return back_elem_->n;
}
return 0;
}
// True, если очередь пуста, иначе False
bool empty() const noexcept {
return front_elem_ == nullptr;
}
// Оператор приведения к типу bool
explicit operator bool() {
return front_elem_ != nullptr;
}
// Дружественный оператор для вывода содержимого очереди в поток ostream (cout, ...)
friend std::ostream &operator<<(std::ostream &os, const Queue &arg) {
queue *t = arg.front_elem_;
if (t) {
os << t->n << ": [" << *t->elem << "]";
while (t->child) {
os << ' ' << t->child->n << ": [" << *t->child->elem << "]";
t = t->child;
}
}
return os;
}
friend void swap(Queue &first, Queue &second) noexcept {
std::swap(first.front_elem_, second.front_elem_);
std::swap(first.back_elem_, second.back_elem_);
}
};
int main() {
Queue<double> queueA, queueB;
// Добавление элементов на верх
queueA.push(111).push(222).push(333).push(444);
queueB.push(444).push(555).push(666);
// Отображение элементов очереди на экране
cout << "Queue A: " << queueA << endl;
cout << "Queue B: " << queueB << endl;
// Доступ к первому и последнему элементу очереди и удаление первого элемента
cout << "Queue A [front() and back(), pop()]: " << queueA.front() << ", " << queueA.back() << endl;
queueA.pop();
cout << "Queue B [front() and back(), pop()]: " << queueB.front() << ", " << queueB.back() << endl;
queueB.pop();
// Конструктор копирования
Queue<double> queueC(queueA);
cout << "Queue (after copy): " << queueA << " (" << queueA.front() << ", " << queueA.back() << ")\n";
cout << "Copy ^ (constructor): " << queueC << " (" << queueC.front() << ", " << queueC.back() << ")\n";
// Оператор копирования
queueC = queueB;
cout << "Queue (after copy): " << queueB << " (" << queueB.front() << ", " << queueB.back() << ")\n";
cout << "Copy ^ (assignment): " << queueC << " (" << queueC.front() << ", " << queueC.back() << ")\n";
// Конструктор перемещения
Queue<double> queueD(std::move(queueA));
cout << "Queue (after move): " << queueA << endl;
cout << "Move ^ (constructor): " << queueD << " (" << queueD.front() << ", " << queueD.back() << ")\n";
// Оператор перемещения
queueC = std::move(queueB);
cout << "Queue (after move): " << queueB << endl;
cout << "Move ^ (assignment): " << queueC << " (" << queueC.front() << ", " << queueC.back() << ")\n";
// Размер очереди
cout << "Queue D (size): " << queueD.size() << " (isEmpty ? " << ( queueD.empty() ? "TRUE" : "FALSE" ) << ")\n";
cout << "Queue C (size): " << queueC.size() << " (isEmpty ? " << ( queueC.empty() ? "TRUE" : "FALSE" ) << ")\n";
queueD.pop(), queueD.pop(), queueD.pop();
queueC.clear();
cout << "Queue D (size after pop): " << queueD.size() << " (isEmpty ? " << ( queueD.empty() ? "TRUE" : "FALSE" )
<< ")\n";
cout << "Queue C (size after pop): " << queueC.size() << " (isEmpty ? " << ( queueC.empty() ? "TRUE" : "FALSE" )
<< ")\n";
// Работа деструктора...
queueD.push(111).push(222).push(333).push(444);
}
Соседние файлы в папке Решения лабораторных работ (местами есть ошибки)