Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <algorithm>
- #include <cassert>
- #include <cstddef>
- #include <iterator>
- #include <string>
- #include <utility>
- #include <list>
- #include <forward_list>
- using namespace std;
- template <typename Type>
- class SingleLinkedList
- {
- // Узел списка
- struct Node {
- Node() = default;
- Node(const Type& val, Node* next)
- : value(val)
- , next(next) {
- }
- Type value;
- Node* next = nullptr;
- };
- // Шаблон класса «Базовый Итератор».
- // Определяет поведение итератора на элементы односвязного списка
- // ValueType — совпадает с Type (для Iterator) либо с const Type (для ConstIterator)
- template <typename ValueType>
- class BasicIterator
- {
- // Класс списка объявляется дружественным, чтобы из методов списка
- // был доступ к приватной области итератора
- friend class SingleLinkedList;
- // Конвертирующий конструктор итератора из указателя на узел списка
- explicit BasicIterator(Node* node)
- {
- /*assert(false);*/
- // Реализуйте конструктор самостоятельно
- node_ = node;
- }
- public:
- // Объявленные ниже типы сообщают стандартной библиотеке о свойствах этого итератора
- // Категория итератора — forward iterator
- // (итератор, который поддерживает операции инкремента и многократное разыменование)
- using iterator_category = std::forward_iterator_tag;
- // Тип элементов, по которым перемещается итератор
- using value_type = Type;
- // Тип, используемый для хранения смещения между итераторами
- using difference_type = std::ptrdiff_t;
- // Тип указателя на итерируемое значение
- using pointer = ValueType*;
- // Тип ссылки на итерируемое значение
- using reference = ValueType&;
- BasicIterator() = default;
- // Конвертирующий конструктор/конструктор копирования
- // При ValueType, совпадающем с Type, играет роль копирующего конструктора
- // При ValueType, совпадающем с const Type, играет роль конвертирующего конструктора
- BasicIterator(const BasicIterator<Type>& other) noexcept
- {
- node_ = other.node_;
- }
- // Чтобы компилятор не выдавал предупреждение об отсутствии оператора = при наличии
- // пользовательского конструктора копирования, явно объявим оператор = и
- // попросим компилятор сгенерировать его за нас
- BasicIterator& operator=(const BasicIterator& rhs) = default;
- // Оператор сравнения итераторов (в роли второго аргумента выступает константный итератор)
- // Два итератора равны, если они ссылаются на один и тот же элемент списка либо на end()
- [[nodiscard]] bool operator==(const BasicIterator<const Type>& rhs) const noexcept {
- return node_ == rhs.node_;
- }
- // Оператор проверки итераторов на неравенство
- // Противоположен !=
- [[nodiscard]] bool operator!=(const BasicIterator<const Type>& rhs) const noexcept {
- return node_ != rhs.node_;
- }
- // Оператор сравнения итераторов (в роли второго аргумента итератор)
- // Два итератора равны, если они ссылаются на один и тот же элемент списка либо на end()
- [[nodiscard]] bool operator==(const BasicIterator<Type>& rhs) const noexcept {
- return node_ == rhs.node_;
- }
- //// Оператор проверки итераторов на неравенство
- //// Противоположен !=
- [[nodiscard]] bool operator!=(const BasicIterator<Type>& rhs) const noexcept {
- return node_ != rhs.node_;
- }
- // Оператор прединкремента. После его вызова итератор указывает на следующий элемент списка
- // Возвращает ссылку на самого себя
- // Инкремент итератора, не указывающего на существующий элемент списка, приводит к неопределённому поведению
- BasicIterator& operator++() noexcept {
- node_ = node_->next;
- return *this;
- }
- // Оператор постинкремента. После его вызова итератор указывает на следующий элемент списка
- // Возвращает прежнее значение итератора
- // Инкремент итератора, не указывающего на существующий элемент списка,
- // приводит к неопределённому поведению
- BasicIterator operator++(int) noexcept
- {
- BasicIterator temp(*this);
- node_ = node_->next;
- return temp;
- }
- // Операция разыменования. Возвращает ссылку на текущий элемент
- // Вызов этого оператора у итератора, не указывающего на существующий элемент списка,
- // приводит к неопределённому поведению
- /* Операции* и->для доступа к элементу списка.Возвращают ссылку и указатель на значение, хранящееся в списке,
- а не на весь узел списка, задаваемый вложенной структурой Node.
- Помните, итераторы должны скрывать внутреннее устройство контейнера от внешнего мира.*/
- [[nodiscard]] reference operator*() const noexcept
- {
- return node_->value;
- }
- // Операция доступа к члену класса. Возвращает указатель на текущий элемент списка
- // Вызов этого оператора у итератора, не указывающего на существующий элемент списка,
- // приводит к неопределённому поведению
- [[nodiscard]] pointer operator->() const noexcept
- {
- return &node_->value;
- }
- //using pointer = ValueType*;
- //// Тип ссылки на итерируемое значение
- //using reference = ValueType&;
- private:
- Node* node_ = nullptr;
- };
- public:
- SingleLinkedList() :head_({}), size_(0)
- {
- }
- SingleLinkedList(std::initializer_list<Type> values) {
- // Реализуйте конструктор самостоятельно
- SingleLinkedList reverse_tmp;
- for (auto it = values.begin(); it != values.end(); ++it)
- {
- reverse_tmp.PushFront(*it);
- }
- SingleLinkedList tmp;
- for (auto it = reverse_tmp.begin(); it != reverse_tmp.end(); ++it)
- {
- tmp.PushFront(*it);
- }
- /* скопировать внутрь tmp элементы other */
- // После того как элементы скопированы, обмениваем данные текущего списка и tmp
- swap(tmp);
- }
- SingleLinkedList(const SingleLinkedList& other) {
- // Сначала надо удостовериться, что текущий список пуст
- // assert(size_ == 0 && head_.next_node == nullptr);
- SingleLinkedList reverse_tmp;
- for (auto it = other.begin(); it != other.end(); ++it)
- {
- reverse_tmp.PushFront(*it);
- }
- SingleLinkedList tmp;
- for (auto it = reverse_tmp.begin(); it != reverse_tmp.end(); ++it)
- {
- tmp.PushFront(*it);
- }
- /* скопировать внутрь tmp элементы other */
- // После того как элементы скопированы, обмениваем данные текущего списка и tmp
- swap(tmp);
- // Теперь tmp пуст, а текущий список содержит копию элементов other
- }
- SingleLinkedList& operator=(const SingleLinkedList& rhs) {
- // Реализуйте присваивание самостоятельно
- if (this != &rhs)
- {
- SingleLinkedList temp(rhs);
- temp.swap(*this);
- }
- return *this;
- }
- // Возвращает количество элементов в списке за время O(1)
- [[nodiscard]] size_t GetSize() const noexcept {
- // Заглушка. Реализуйте метод самостоятельно
- //assert(false);
- //return 42;
- return size_;
- }
- // Обменивает содержимое списков за время O(1)
- void swap(SingleLinkedList& other) noexcept {
- // Реализуйте обмен содержимого списков самостоятельно
- std::swap(other.size_, size_);
- std::swap(head_.next, other.head_.next);
- /*std::swap(this->GetSize(), other.GetSize());*/
- }
- // Вставляет элемент value в начало списка за время O(1)
- void PushFront(const Type& value)
- {
- // Реализуйте метод самостоятельно
- /* Node head_;*/
- head_.next = new Node(value, head_.next);
- ++size_;
- }
- // Очищает список за время O(N)
- void Clear() noexcept
- {
- // Реализуйте метод самостоятельно
- while (head_.next != nullptr)
- {
- Node* temp = head_.next;
- head_.next = head_.next->next;
- delete temp;
- --size_;
- }
- }
- // Сообщает, пустой ли список за время O(1)
- [[nodiscard]] bool IsEmpty() const noexcept {
- // Заглушка. Реализуйте метод самостоятельно
- /* assert(false);
- return false;*/
- if (size_ == 0)
- {
- return true;
- }
- return false;
- }
- ~SingleLinkedList()
- {
- Clear();
- }
- using value_type = Type;
- using reference = value_type&;
- using const_reference = const value_type&;
- // Итератор, допускающий изменение элементов списка
- using Iterator = BasicIterator<Type>;
- // Константный итератор, предоставляющий доступ для чтения к элементам списка
- using ConstIterator = BasicIterator<const Type>;
- // Возвращает итератор, ссылающийся на первый элемент
- // Если список пустой, возвращённый итератор будет равен end()
- [[nodiscard]] Iterator begin() noexcept {
- return Iterator(head_.next);
- }
- // Возвращает итератор, указывающий на позицию, следующую за последним элементом односвязного списка
- // Разыменовывать этот итератор нельзя — попытка разыменования приведёт к неопределённому поведению
- [[nodiscard]] Iterator end() noexcept {
- return Iterator(nullptr);
- }
- // Возвращает константный итератор, ссылающийся на первый элемент
- // Если список пустой, возвращённый итератор будет равен end()
- // Результат вызова эквивалентен вызову метода cbegin()
- [[nodiscard]] ConstIterator begin() const noexcept {
- return ConstIterator(head_.next);
- }
- // Возвращает константный итератор, указывающий на позицию, следующую за последним элементом односвязного списка
- // Разыменовывать этот итератор нельзя — попытка разыменования приведёт к неопределённому поведению
- // Результат вызова эквивалентен вызову метода cend()
- [[nodiscard]] ConstIterator end() const noexcept {
- return ConstIterator(nullptr);
- }
- // Возвращает константный итератор, ссылающийся на первый элемент
- // Если список пустой, возвращённый итератор будет равен cend()
- [[nodiscard]] ConstIterator cbegin() const noexcept {
- return ConstIterator(head_.next);
- }
- // Возвращает константный итератор, указывающий на позицию, следующую за последним элементом односвязного списка
- // Разыменовывать этот итератор нельзя — попытка разыменования приведёт к неопределённому поведению
- [[nodiscard]] ConstIterator cend() const noexcept {
- return ConstIterator(nullptr);
- }
- // Возвращает итератор, указывающий на позицию перед первым элементом односвязного списка.
- // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
- [[nodiscard]] Iterator before_begin() noexcept {
- // Реализуйте самостоятельно
- return Iterator(&head_);
- }
- // Возвращает константный итератор, указывающий на позицию перед первым элементом односвязного списка.
- // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
- [[nodiscard]] ConstIterator cbefore_begin() const noexcept {
- //Реализуйте самостоятельно
- return ConstIterator{ const_cast<Node*>(&head_) };
- }
- //// Возвращает константный итератор, указывающий на позицию перед первым элементом односвязного списка.
- //// Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
- [[nodiscard]] ConstIterator before_begin() const noexcept {
- //Реализуйте самостоятельно
- return cbefore_begin();
- }
- void PopFront() noexcept {
- // Реализуйте метод самостоятельно
- Node* temp = head_.next;
- head_.next = head_.next->next;
- delete temp;
- --size_;
- }
- /*Вставляет элемент value после элемента, на который указывает pos.
- Возвращает итератор на вставленный элемент
- Если при создании элемента будет выброшено исключение, список останется в прежнем состоянии */
- Iterator InsertAfter(ConstIterator pos, const Type& value) {
- // Заглушка. Реализуйте метод самостоятельно
- pos.node_->next = new Node(value, pos.node_->next);
- ++size_;
- return Iterator(pos.node_->next);
- }
- /*Удаляет элемент, следующий за pos.
- Возвращает итератор на элемент, следующий за удалённым*/
- Iterator EraseAfter(ConstIterator pos) noexcept {
- // Заглушка. Реализуйте метод самостоятельно
- auto to_return = pos.node_->next->next;
- auto to_delete = pos.node_->next;
- pos.node_->next = pos.node_->next->next;
- delete to_delete;
- --size_;
- return Iterator(to_return);
- }
- Node* merge(Node* head_one, Node* head_two)
- {
- Node* head_three = nullptr;
- if (head_one == nullptr)
- {
- return head_two;
- }
- if (head_two == nullptr)
- {
- return head_one;
- }
- if (head_one->value < head_two->value)
- {
- head_three = head_one;
- head_three->next = merge(head_one->next, head_two);
- }
- else
- {
- head_three = head_two;
- head_three->next = merge(head_one, head_two->next);
- }
- return head_three;
- }
- Node* mergesort(Node* head)
- {
- Node* head_one;
- Node* head_two;
- if ((head == nullptr) || (head->next == nullptr))
- {
- return head;
- }
- head_one = head;
- head_two = head->next;
- while ((head_two != nullptr) && (head_two->next != nullptr))
- {
- head = head->next;
- head_two = head_two->next->next;
- }
- head_two = head->next;
- head->next = nullptr;
- return merge(mergesort(head_one), mergesort(head_two));
- }
- void mergesort()
- {
- head_.next = mergesort(head_.next);
- }
- void Reverse()
- {
- Node* temp = head_.next; // текущий узел
- Node* prev = nullptr; // предыдущий узел
- Node* nexto; // следующий узел
- while (temp != nullptr)
- {
- nexto = temp->next; // 250 (запоминаем значение слеующего узла) для того чтобы разрушить связь
- if (nexto == nullptr)
- {
- head_.next = temp;
- }
- temp->next = prev; //разрушали связь между узлами, (разворачиваем узлы) где было 250 сейчас nullptr
- prev = temp; // на след. итерации пред узлом будет текущий
- temp = nexto; // переходим на след итерацию
- }
- }
- private:
- // Фиктивный узел, используется для вставки "перед первым элементом"
- Node head_;
- size_t size_;
- };
- template <typename Type>
- void swap(SingleLinkedList<Type>& lhs, SingleLinkedList<Type>& rhs) noexcept {
- // Реализуйте обмен самостоятельно
- lhs.swap(rhs);
- }
- template <typename Type>
- bool operator==(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
- if (lhs.GetSize() != rhs.GetSize())
- {
- return false;
- }
- return equal(lhs.begin(), lhs.begin(), rhs.begin());
- }
- template <typename Type>
- bool operator!=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
- return !(lhs == rhs);
- }
- template <typename Type>
- bool operator<(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
- // Заглушка. Реализуйте сравнение самостоятельно
- return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
- }
- template <typename Type>
- bool operator<=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
- // Заглушка. Реализуйте сравнение самостоятельно
- return (lhs < rhs) || (lhs == rhs);
- }
- template <typename Type>
- bool operator>(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
- // Заглушка. Реализуйте сравнение самостоятельно
- return !(lhs < rhs);
- }
- template <typename Type>
- bool operator>=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
- // Заглушка. Реализуйте сравнение самостоятельно
- return (lhs > rhs) || (lhs == rhs);
- }
- // Эта функция проверяет работу класса SingleLinkedList
- void Test4() {
- struct DeletionSpy {
- ~DeletionSpy() {
- if (deletion_counter_ptr) {
- ++(*deletion_counter_ptr);
- }
- }
- int* deletion_counter_ptr = nullptr;
- };
- // Проверка PopFront
- {
- SingleLinkedList<int> numbers{ 3, 14, 15, 92, 6 };
- numbers.PopFront();
- assert((numbers == SingleLinkedList<int>{14, 15, 92, 6}));
- SingleLinkedList<DeletionSpy> list;
- list.PushFront(DeletionSpy{});
- int deletion_counter = 0;
- list.begin()->deletion_counter_ptr = &deletion_counter;
- assert(deletion_counter == 0);
- list.PopFront();
- assert(deletion_counter == 1);
- }
- // Доступ к позиции, предшествующей begin
- {
- SingleLinkedList<int> empty_list;
- const auto& const_empty_list = empty_list;
- assert(empty_list.before_begin() == empty_list.cbefore_begin());
- assert(++empty_list.before_begin() == empty_list.begin());
- assert(++empty_list.cbefore_begin() == const_empty_list.begin());
- SingleLinkedList<int> numbers{ 1, 2, 3, 4 };
- const auto& const_numbers = numbers;
- assert(numbers.before_begin() == numbers.cbefore_begin());
- assert(++numbers.before_begin() == numbers.begin());
- assert(++numbers.cbefore_begin() == const_numbers.begin());
- }
- // Вставка элемента после указанной позиции
- { // Вставка в пустой список
- {
- SingleLinkedList<int> lst;
- const auto inserted_item_pos = lst.InsertAfter(lst.before_begin(), 123);
- assert((lst == SingleLinkedList<int>{123}));
- assert(inserted_item_pos == lst.begin());
- assert(*inserted_item_pos == 123);
- }
- // Вставка в непустой список
- {
- SingleLinkedList<int> lst{ 1, 2, 3 };
- auto inserted_item_pos = lst.InsertAfter(lst.before_begin(), 123);
- assert(inserted_item_pos == lst.begin());
- assert(inserted_item_pos != lst.end());
- assert(*inserted_item_pos == 123);
- assert((lst == SingleLinkedList<int>{123, 1, 2, 3}));
- inserted_item_pos = lst.InsertAfter(lst.begin(), 555);
- assert(++SingleLinkedList<int>::Iterator(lst.begin()) == inserted_item_pos);
- assert(*inserted_item_pos == 555);
- assert((lst == SingleLinkedList<int>{123, 555, 1, 2, 3}));
- };
- }
- // Вспомогательный класс, бросающий исключение после создания N-копии
- struct ThrowOnCopy {
- ThrowOnCopy() = default;
- explicit ThrowOnCopy(int& copy_counter) noexcept
- : countdown_ptr(©_counter) {
- }
- ThrowOnCopy(const ThrowOnCopy& other)
- : countdown_ptr(other.countdown_ptr) //
- {
- if (countdown_ptr) {
- if (*countdown_ptr == 0) {
- throw std::bad_alloc();
- }
- else {
- --(*countdown_ptr);
- }
- }
- }
- // Присваивание элементов этого типа не требуется
- ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
- // Адрес счётчика обратного отсчёта. Если не равен nullptr, то уменьшается при каждом копировании.
- // Как только обнулится, конструктор копирования выбросит исключение
- int* countdown_ptr = nullptr;
- };
- // Проверка обеспечения строгой гарантии безопасности исключений
- {
- bool exception_was_thrown = false;
- for (int max_copy_counter = 10; max_copy_counter >= 0; --max_copy_counter) {
- SingleLinkedList<ThrowOnCopy> list{ ThrowOnCopy{}, ThrowOnCopy{}, ThrowOnCopy{} };
- try {
- int copy_counter = max_copy_counter;
- list.InsertAfter(list.cbegin(), ThrowOnCopy(copy_counter));
- assert(list.GetSize() == 4u);
- }
- catch (const std::bad_alloc&) {
- exception_was_thrown = true;
- assert(list.GetSize() == 3u);
- break;
- }
- }
- assert(exception_was_thrown);
- }
- // Удаление элементов после указанной позиции
- {
- {
- SingleLinkedList<int> lst{ 1, 2, 3, 4 };
- const auto& const_lst = lst;
- const auto item_after_erased = lst.EraseAfter(const_lst.cbefore_begin());
- assert((lst == SingleLinkedList<int>{2, 3, 4}));
- assert(item_after_erased == lst.begin());
- }
- {
- SingleLinkedList<int> lst{ 1, 2, 3, 4 };
- const auto item_after_erased = lst.EraseAfter(lst.cbegin());
- assert((lst == SingleLinkedList<int>{1, 3, 4}));
- assert(item_after_erased == (++lst.begin()));
- }
- {
- SingleLinkedList<int> lst{ 1, 2, 3, 4 };
- const auto item_after_erased = lst.EraseAfter(++(++lst.cbegin()));
- assert((lst == SingleLinkedList<int>{1, 2, 3}));
- assert(item_after_erased == lst.end());
- }
- {
- SingleLinkedList<DeletionSpy> list{ DeletionSpy{}, DeletionSpy{}, DeletionSpy{} };
- auto after_begin = ++list.begin();
- int deletion_counter = 0;
- after_begin->deletion_counter_ptr = &deletion_counter;
- assert(deletion_counter == 0u);
- list.EraseAfter(list.cbegin());
- assert(deletion_counter == 1u);
- }
- }
- }
- int main() {
- //Test4();
- SingleLinkedList <int> sll = { 1,2,3,4,5 };
- sll.Reverse();
- sll.mergesort();
- sll.Reverse();
- for (auto el : sll)
- {
- cout << el << " ";
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement