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

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

// Стек на основе динамического одномерного массива
// Принцип:
// push -> добавляет элемент в начало (на самом деле в конец массива values_)
// pop  -> удаляет элемент из начала (на самом деле из конца массива values_)
template <class T>
class StackArray {
 private:

    // Текущий размер стека
    size_t n_;
    // Резервируемый размер стека (m_ >= n_)
    size_t m_ = 10;
    // Указатель на массив из m_ элементов
    T *values_ = nullptr;

 protected:

    // Стандартное количество резервируемых элементов
    size_t standart = 10;

 public:

    // Конструктор
    explicit StackArray() {
        n_ = 0;
        values_ = new T[m_] {0};
    }

    // Конструктор копирования
    StackArray(const StackArray &arg) {
        n_ = arg.n_, m_ = arg.m_;
        values_ = new T[m_] {0};
        std::copy(arg.values_, arg.values_ + n_, values_);
    }

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

    // Конструктор перемещения
    StackArray(StackArray &&arg) noexcept {
        n_ = arg.n_, m_ = arg.m_, values_ = arg.values_, standart = arg.standart;
        arg.n_ = 0, arg.m_ = 0, arg.values_ = nullptr, arg.standart = 10;
    }

    // Оператор перемещения
    StackArray &operator=(StackArray &&arg) noexcept {
        if (this != &arg) {
            swap(*this, arg);
            delete[] arg.values_, arg.values_ = nullptr;
            arg.n_ = 0;
        }
        return *this;
    }

    // Деструктор
    virtual ~StackArray() {
        delete[] values_;
    }

    // Получение размера стека
    size_t size() const { return n_; }

    // Вставка элемента "на верх" (на самом деле в конец)
    StackArray &push(const T &d) {
        if (n_ < m_) {
            values_[n_] = d, ++n_;
            return *this;
        }
        T *b = values_;
        values_ = new T[m_ * 2] {0};
        memcpy(values_, b, sizeof(T) * n_);
        delete[] b;
        m_ *= 2;
        return *this;
    }

    // Получение доступа к верхнему элементу
    T &top() const noexcept(false) {
        if (values_) {
            return values_[n_ - 1];
        } else { throw std::out_of_range("StackArray. Method top. Out of range"); }
    }

    // Очистка стека
    void clear() {
        delete[] values_;
        values_ = new T[standart] {0};
        n_ = 0, m_ = standart;
    }

    // Пустой ли стек
    bool empty() const noexcept { return n_ == 0; }

    // Удаление и возвращение копии элемента из верха (на самом деле последнего)
    T pop() {
        T d = 0;
        if (n_ > 0) {
            d = values_[n_ - 1], --n_;
        }
        return d;
    }

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

    // // Дружественный оператор для вывода стека в ostream (cout, ...) [вывод массива в обратном порядке]
    friend std::ostream &operator<<(std::ostream &os, const StackArray &arg) {
        if (arg.n_ > 0) {
            os << arg.n_ << " : [" << arg.values_[arg.n_ - 1] << "]";
        }
        for (size_t i = 2; i <= arg.n_; ++i) {
            os << ", " << ( arg.n_ - i + 1 ) << " : [" << arg.values_[arg.n_ - i] << ']';
        }
        return os;
    }

    friend void swap(StackArray &first, StackArray &second) noexcept {
        std::swap(first.n_, second.n_);
        std::swap(first.m_, second.m_);
        std::swap(first.values_, second.values_);
        std::swap(first.standart, second.standart);
    }
};

int main() {
    StackArray<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();
    // Конструктор копирования
    StackArray<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";
    // Конструктор перемещения
    StackArray<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(111).push(222).push(333).push(444);
}