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

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

// Простая реализация однонаправленного списка
template <class T>
class List {
 protected:

    // Структура "список"
    struct list {
        T *elem;
        list *next;
    };

    // Полная очистка списка
    void standart_clear() {
        if (data_) {
            list **next = &data_;
            for (size_t i = 0; i < n_; ++i) {
                delete ( *next )->elem; // Освобождаем очередной соответствующий элемент родителя
                list *t = ( *next )->next; // Передвигаемся к child в t
                delete *next, *next = t; // Освобождаем родителя, next = t (child)
            }
            data_ = nullptr;
        }
        n_ = 0;
    }

 private:

    // Текущий размер списка
    size_t n_ = 0;
    // Указатель на структуру list
    list *data_ = nullptr;

 public:

    // Конструктор
    explicit List(size_t n = 0) : n_(n) {
        if (n >= 0) {
            data_ = nullptr;
            list **next = &data_;
            for (size_t i = 0; i < n; ++i) {
                *next = new list {new T(), nullptr}; // Выделяем память для родителя
                next = &( ( *next )->next ); // Переходим к его child
            }
            return;
        }
        throw std::bad_array_new_length();
    }

    // Конструктор копирования
    List(const List &arg) {
        n_ = 0;
        if (arg.data_) {
            n_ = arg.n_;
            data_ = new list {new T(*arg.data_->elem), nullptr};
            list **next = &data_->next, **arg_next = &arg.data_->next;
            for (size_t i = 1; i < n_; ++i) {
                *next = new list {new T(*( *arg_next )->elem), nullptr};
                next = &( ( *next )->next );
                arg_next = &( ( *arg_next )->next );
            }
        }
    }

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

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

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

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

    // Очистка списка
    void clear() {
        standart_clear();
    }

    // Получает элемент списка по индексу [сложность T(n_)]
    T &operator[](const size_t &idx) noexcept(false) {
        if (idx >= 0 && idx < n_) {
            list **next = &data_;
            for (size_t i = 0; i < idx; ++i) {
                next = &( ( *next )->next );
            }
            return *( *next )->elem;
        }
        throw std::out_of_range("List. Operator[]. Out of range");
    }

    // Вставляет элемент ELEM в позицию IDX [сложность T(n_)]
    void insert(const size_t &idx, const T &elem) noexcept(false) {
        if (idx >= 0 && idx <= n_) {
            if (data_) {
                list **next = &data_;
                for (size_t i = 0; i < idx; ++i) {
                    next = &( ( *next )->next );
                }
                *next = new list {new T {elem}, *next};
                ++n_;
                return;
            }
            data_ = new list {new T {elem}, nullptr};
            ++n_;
            return;
        }
        throw std::out_of_range("List. Method insert. Out of range");
    }

    // Удаляет элемент с индексом IDX [сложность T(n_)]
    void erase(const size_t &idx) noexcept(false) {
        if (idx > 0 && idx < n_) {
            list **next = &data_;
            for (size_t i = 1; i < idx; ++i) {
                next = &( ( *next )->next );
            }
            list *temp = ( ( *next )->next ? ( *next )->next->next : nullptr );
            delete ( *next )->next, ( *next )->next = temp;
            --n_;
            return;
        } else if (idx == 0 && data_) {
            list *temp = data_->next;
            delete data_, data_ = temp;
            --n_;
            return;
        }
        throw std::out_of_range("List. Method erase. Out of range");
    }

    // Возвращает размер списка
    size_t size() const noexcept {
        return n_;
    }

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

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

    // Вывод содержимого списка в поток ostream (cout, ...)
    friend std::ostream &operator<<(std::ostream &os, List &arg) {
        list **next = &arg.data_;
        if (*next) {
            os << *( *next )->elem;
            next = &( ( *next )->next );
            for (size_t i = 1; i < arg.n_; ++i) {
                os << ' ' << *( *next )->elem;
                next = &( ( *next )->next );
            }
        }
        return os;
    }

    friend void swap(List &first, List &second) noexcept {
        std::swap(first.n_, second.n_);
        std::swap(first.data_, second.data_);
    }
};

int main() {
    List<double> listA, listB(5);
    // Добавление и удаление элементов
    for (size_t i = 0; i < 5; ++i) { listA.insert(listA.size(), ( i + 1 )); }
    for (size_t i = 0; i < 5; ++i) { listA.erase(0); }
    for (size_t i = 0; i < 5; ++i) { listA.insert(( i + 1 ) / 2, i + 1); }
    for (size_t i = 0; i < 5; ++i) { listB[i] = i + 1; }
    // Отображение содержимого списков
    cout << "List A: " << listA << endl;
    cout << "List B: " << listB << endl;
    // Доступ к любому элементу [сложность T(n_)]
    cout << "List A[0]: " << ( listA.size() > 0 ? listA[0] : -0 ) << endl;
    cout << "List A[" << listA.size() - 1 << "]: " << ( listA.size() - 1 > 0 ? listA[listA.size() - 1] : -0 ) << endl;
    cout << "List B[0]: " << ( listB.size() > 0 ? listB[0] : -0 ) << endl;
    cout << "List B[" << listB.size() - 1 << "]: " << ( listB.size() - 1 > 0 ? listB[listB.size() - 1] : -0 ) << endl;
    // Конструктор копирования
    List<double> listC(listA);
    cout << "List (after copy): " << listA << endl;
    cout << "Copy ^ (constructor): " << listC << endl;
    // Оператор копирования
    listC = listB;
    cout << "List (after copy): " << listB << endl;
    cout << "Copy ^ (assignment): " << listC << endl;
    // Конструктор перемещения
    List<double> listD(std::move(listA));
    cout << "List (after move): " << listA << endl;
    cout << "Move ^ (constructor): " << listD << endl;
    // Оператор перемещения
    listC = std::move(listB);
    cout << "List (after move): " << listB << endl;
    cout << "Move ^ (assignment): " << listC << endl;
    // Размер списка
    cout << "List D (size): " << listD.size() << " (isEmpty ? " << ( listD.empty() ? "TRUE" : "FALSE" ) << ")\n";
    cout << "List C (size): " << listC.size() << " (isEmpty ? " << ( listC.empty() ? "TRUE" : "FALSE" ) << ")\n";
    // Очистка списка
    listD.erase(4);
    listD.erase(3);
    listD.erase(2);
    listD.erase(1);
    listD.erase(0);
    listC.clear();
    cout << "List D (size after pop): " << listD.size() << " (isEmpty ? " << ( listD.empty() ? "TRUE" : "FALSE" )
         << ")\n";
    cout << "List C (size after pop): " << listC.size() << " (isEmpty ? " << ( listC.empty() ? "TRUE" : "FALSE" )
         << ")\n";
    // Работа деструктора...
    listD.insert(0, 1000);
    listD.insert(0, 1200);
    listD.insert(0, 1300);
}