Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
34
Добавлен:
10.09.2019
Размер:
6.38 Кб
Скачать
#include <iostream>
#include <stdexcept>

using std::cin;
using std::cout;
using std::endl;

// Стек на основе однонаправленного списка
template <class T>
class Stack {
 protected:

    struct stack {
        size_t n;
        T *elem;
        stack *child;
    };

 private:

    stack *data_ = nullptr;

 public:

    // Конструктор
    Stack() = default;

    // Конструктор копирования
    Stack(const Stack &arg) {
        if (arg.data_ && arg.data_->n > 0) {
            stack *t = arg.data_;
            T *temp = new T[arg.data_->n]; // Выделяем память под массив
            for (size_t i = 0; i < arg.data_->n; ++i) {
                temp[i] = *t->elem, t = t->child; // Добавляем очередной элемент стека в массив
            }
            for (size_t i = 0; i < arg.data_->n; ++i) {
                push(temp[arg.data_->n - i - 1]); // Добавляем элементы массива с конца в стек
            }
            delete[] temp;
        }
    }

    // Оператор копирования
    Stack &operator=(const Stack &arg) {
        Stack temp(arg);
        swap(*this, temp);
        return *this;
    }

    // Конструктор перемещения
    Stack(Stack &&arg) noexcept {
        data_ = arg.data_;
        arg.data_ = nullptr;
    }

    // Оператор перемещения
    Stack &operator=(Stack &&arg) noexcept {
        if (this != &arg) {
            swap(*this, arg);
            arg.clear();
        }
        return *this;
    }

    // Деструктор
    virtual ~Stack() {
        clear();
    }

    // Очистка стека
    void clear() {
        if (data_) {
            stack *child = data_->child;
            while (child) {
                delete child->elem;
                stack *next = child->child;
                delete child;
                child = next;
            }
            delete data_, data_ = nullptr;
        }
    }

    // Вставляет элемент на верх
    Stack &push(const T &elem) {
        if (data_) {
            data_ = new stack {data_->n + 1, new T {elem}, data_};
            return *this;
        }
        data_ = new stack {1, new T {elem}, nullptr};
        return *this;
    }

    // Доступ к верхнему элементу
    T &top() const noexcept(false) {
        if (data_) {
            return *data_->elem;
        }
        throw std::out_of_range("Stack. Method top. Out of range");
    }

    // Удаляет верхний элемент
    void pop() noexcept(false) {
        if (data_) {
            delete data_->elem;
            stack *child = data_->child;
            delete data_;
            data_ = child;
            return;
        }
        throw std::out_of_range("Stack. Method pop. Out of range");
    }

    // Возвращает размер стека
    size_t size() const {
        if (data_) {
            return data_->n;
        }
        return 0;
    }

    // True, если стек пустой, иначе False
    bool empty() const noexcept {
        return data_ == nullptr;
    }

    // Оператор приведения к типу bool
    explicit operator bool() {
        return data_ != nullptr;
    }

    // Вывод содержимого стека в поток ostream (cout, ...)
    friend std::ostream &operator<<(std::ostream &os, const Stack &arg) {
        stack *t = arg.data_;
        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(Stack &first, Stack &second) noexcept {
        std::swap(first.data_, second.data_);
    }
};

int main() {
    Stack<double> stackA, stackB;
    // Добавление элементов на верх
    stackA.push(111).push(222).push(333).push(444);
    stackB.push(444).push(555).push(666);
    // Отображение содержимого стеков
    cout << "Stack A: " << stackA << endl;
    cout << "Stack B: " << stackB << endl;
    // Доступ к вершине стека и удаление верхнего элемента
    cout << "Stack A [top(), pop()]: " << stackA.top() << endl;
    stackA.pop();
    cout << "Stack B [top(), pop()]: " << stackB.top() << endl;
    stackB.pop();
    // Конструктор копирования
    Stack<double> stackC(stackA);
    cout << "Stack (after copy): " << stackA << " (top: " << stackA.top() << ")\n";
    cout << "Copy ^ (constructor): " << stackC << " (top: " << stackC.top() << ")\n";
    // Оператор копирования
    stackC = stackB;
    cout << "Stack (after copy): " << stackB << " (top: " << stackB.top() << ")\n";
    cout << "Copy ^ (assignment): " << stackC << " (top: " << stackC.top() << ")\n";
    // Конструктор перемещения
    Stack<double> stackD(std::move(stackA));
    cout << "Stack (after move): " << stackA << endl;
    cout << "Move ^ (constructor): " << stackD << " (top: " << stackD.top() << ")\n";
    // Оператор перемещения
    stackC = std::move(stackB);
    cout << "Stack (after move): " << stackB << endl;
    cout << "Move ^ (assignment): " << stackC << " (top: " << stackC.top() << ")\n";
    // Размер стека
    cout << "Stack D (size): " << stackD.size() << " (isEmpty ? " << ( stackD.empty() ? "TRUE" : "FALSE" ) << ")\n";
    cout << "Stack C (size): " << stackC.size() << " (isEmpty ? " << ( stackC.empty() ? "TRUE" : "FALSE" ) << ")\n";
    stackD.pop(), stackD.pop(), stackD.pop();
    stackC.clear();
    cout << "Stack D (size after pop): " << stackD.size() << " (isEmpty ? " << ( stackD.empty() ? "TRUE" : "FALSE" )
         << ")\n";
    cout << "Stack C (size after pop): " << stackC.size() << " (isEmpty ? " << ( stackC.empty() ? "TRUE" : "FALSE" )
         << ")\n";
    // Работа деструктора...
    stackD.push(5).push(6).push(7);
}