Advertisement
chevengur

СПРИНТ № 7 | Односвязный список | Урок 6: Вставка и удаление в произвольной позиции

May 14th, 2024
686
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.32 KB | None | 0 0
  1. #include <cassert>
  2. #include <cstddef>
  3. #include <string>
  4. #include <utility>
  5. #include <iostream>
  6. #include <vector>
  7. #include <algorithm>
  8.  
  9. template <typename Type>
  10. class SingleLinkedList {
  11.     // Узел списка
  12.     struct Node {
  13.         Node() = default;
  14.         Node(const Type& val, Node* next)
  15.             : value(val)
  16.             , next_node(next) {
  17.         }
  18.         Type value;
  19.         Node* next_node = nullptr;
  20.     };
  21.  
  22.  
  23.     template <typename ValueType>
  24.     class BasicIterator {
  25.         // Класс списка объявляется дружественным, чтобы из методов списка
  26.         // был доступ к приватной области итератора
  27.         friend class SingleLinkedList;
  28.  
  29.         // Конвертирующий конструктор итератора из указателя на узел списка
  30.         explicit BasicIterator(Node* node) : node_(node) {
  31.         }
  32.  
  33.     public:
  34.         // Объявленные ниже типы сообщают стандартной библиотеке о свойствах этого итератора
  35.  
  36.         // Категория итератора — forward iterator
  37.         // (итератор, который поддерживает операции инкремента и многократное разыменование)
  38.         using iterator_category = std::forward_iterator_tag;
  39.         // Тип элементов, по которым перемещается итератор
  40.         using value_type = Type;
  41.         // Тип, используемый для хранения смещения между итераторами
  42.         using difference_type = std::ptrdiff_t;
  43.         // Тип указателя на итерируемое значение
  44.         using pointer = ValueType*;
  45.         // Тип ссылки на итерируемое значение
  46.         using reference = ValueType&;
  47.  
  48.         BasicIterator() = default;
  49.  
  50.         BasicIterator(const BasicIterator<Type>& other) noexcept {
  51.             node_ = other.node_;
  52.         }
  53.  
  54.         BasicIterator& operator=(const BasicIterator& rhs) = default;
  55.  
  56.         [[nodiscard]] bool operator==(const BasicIterator<const Type>& rhs) const noexcept {
  57.             return node_ == rhs.node_;
  58.         }
  59.  
  60.         [[nodiscard]] bool operator!=(const BasicIterator<const Type>& rhs) const noexcept {
  61.             return !(node_ == rhs.node_);
  62.  
  63.         }
  64.  
  65.         [[nodiscard]] bool operator==(const BasicIterator<Type>& rhs) const noexcept {
  66.             return node_ == rhs.node_;
  67.         }
  68.  
  69.         [[nodiscard]] bool operator!=(const BasicIterator<Type>& rhs) const noexcept {
  70.             return !(node_ == rhs.node_);
  71.         }
  72.  
  73.         BasicIterator& operator++() noexcept {
  74.             node_ = node_->next_node;
  75.             return *this;
  76.         }
  77.  
  78.         BasicIterator operator++(int) noexcept {
  79.             auto old_value(*this);
  80.             ++(*this);
  81.             return old_value;
  82.         }
  83.  
  84.         [[nodiscard]] reference operator*() const noexcept {
  85.             return node_->value;
  86.         }
  87.  
  88.         [[nodiscard]] pointer operator->() const noexcept {
  89.             return &node_->value;
  90.         }
  91.  
  92.     private:
  93.         Node* node_ = nullptr;
  94.     };
  95.  
  96. public:
  97.  
  98.     using value_type = Type;
  99.     using reference = value_type&;
  100.     using const_reference = const value_type&;
  101.  
  102.     SingleLinkedList() : head_(), size_(0) {};
  103.  
  104.     ~SingleLinkedList() { Clear(); };
  105.  
  106.     template<typename iterator>
  107.     void Initialization(iterator begin, iterator end)
  108.     {
  109.         Node* newnode = &head_;
  110.         for (auto i = begin; i != end; ++i)
  111.         {
  112.             ++size_;
  113.             newnode->next_node = new Node(*i, nullptr);
  114.             newnode = newnode->next_node;
  115.         }
  116.     }
  117.  
  118.     SingleLinkedList(std::initializer_list<Type> values)
  119.     {
  120.         SingleLinkedList currentlist;
  121.         currentlist.Initialization(values.begin(), values.end());
  122.         swap(currentlist);
  123.     }
  124.  
  125.     SingleLinkedList(const SingleLinkedList& other)
  126.     {
  127.         SingleLinkedList currentlist;
  128.         currentlist.Initialization(other.begin(), other.end());
  129.         swap(currentlist);
  130.     }
  131.  
  132.     SingleLinkedList& operator=(const SingleLinkedList& rhs) {
  133.         if (this != &rhs)
  134.         {
  135.             SingleLinkedList currentlist(rhs);
  136.             swap(currentlist);
  137.         }
  138.         return *this;
  139.     }
  140.  
  141.     // Обменивает содержимое списков за время O(1)
  142.     void swap(SingleLinkedList& other) noexcept {
  143.         std::swap(head_.next_node, other.head_.next_node);
  144.         std::swap(size_, other.size_);
  145.     }
  146.  
  147.     void PushFront(const Type& value) {
  148.         head_.next_node = new Node(value, head_.next_node);
  149.         ++size_;
  150.     }
  151.  
  152.     void Clear() noexcept {
  153.         while (head_.next_node)
  154.         {
  155.             Node* new_node = head_.next_node->next_node;
  156.             delete head_.next_node;
  157.             head_.next_node = new_node;
  158.         }
  159.         size_ = 0;
  160.     }
  161.  
  162.     [[nodiscard]] size_t GetSize() const noexcept {
  163.         return size_;
  164.     }
  165.  
  166.     [[nodiscard]] bool IsEmpty() const noexcept {
  167.         return (size_ == 0) ? true : false;
  168.     }
  169.  
  170.     // Итератор, допускающий изменение элементов списка
  171.     using Iterator = BasicIterator<Type>;
  172.     // Константный итератор, предоставляющий доступ для чтения к элементам списка
  173.     using ConstIterator = BasicIterator<const Type>;
  174.  
  175.     [[nodiscard]] Iterator begin() noexcept {
  176.         return Iterator{ head_.next_node };
  177.     }
  178.  
  179.     [[nodiscard]] Iterator end() noexcept {
  180.         return Iterator{ nullptr };
  181.     }
  182.  
  183.     [[nodiscard]] ConstIterator begin() const noexcept {
  184.         return ConstIterator{ head_.next_node };
  185.     }
  186.  
  187.     [[nodiscard]] ConstIterator end() const noexcept {
  188.         return ConstIterator{ nullptr };
  189.     }
  190.  
  191.     [[nodiscard]] ConstIterator cbegin() const noexcept {
  192.         return ConstIterator{ head_.next_node };
  193.     }
  194.  
  195.     [[nodiscard]] ConstIterator cend() const noexcept {
  196.         return ConstIterator{ nullptr };
  197.     }
  198.  
  199.     // Возвращает итератор, указывающий на позицию перед первым элементом односвязного списка.
  200.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  201.     [[nodiscard]] Iterator before_begin() noexcept {
  202.         return Iterator{ &head_ };
  203.     }
  204.  
  205.     // Возвращает константный итератор, указывающий на позицию перед первым элементом односвязного списка.
  206.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  207.     [[nodiscard]] ConstIterator cbefore_begin() const noexcept {
  208.         return ConstIterator{ const_cast<Node*>(&head_) };
  209.     }
  210.  
  211.     // Возвращает константный итератор, указывающий на позицию перед первым элементом односвязного списка.
  212.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  213.     [[nodiscard]] ConstIterator before_begin() const noexcept {
  214.         return ConstIterator{ const_cast<Node*>(&head_) };
  215.     }
  216.  
  217.     /*
  218.      * Вставляет элемент value после элемента, на который указывает pos.
  219.      * Возвращает итератор на вставленный элемент
  220.      * Если при создании элемента будет выброшено исключение, список останется в прежнем состоянии
  221.      */
  222.     Iterator InsertAfter(ConstIterator pos, const Type& value) {
  223.         Node* new_node = pos.node_->next_node;
  224.         pos.node_->next_node = new Node(value, new_node);
  225.         ++size_;
  226.         return Iterator{ pos.node_->next_node }; // исправил, было pos.node_
  227.     }
  228.  
  229.     void PopFront() noexcept {
  230.         if (!IsEmpty())
  231.         {
  232.             Node* current_node = head_.next_node->next_node;
  233.             delete head_.next_node;
  234.             --size_;
  235.             head_.next_node = current_node;
  236.         }
  237.     }
  238.  
  239.     /*
  240.      * Удаляет элемент, следующий за pos.
  241.      * Возвращает итератор на элемент, следующий за удалённым
  242.      */
  243.     Iterator EraseAfter(ConstIterator pos) noexcept {
  244.     if (!IsEmpty())
  245.     {
  246.         Node* helper = pos.node_->next_node->next_node;
  247.         delete pos.node_->next_node;
  248.         --size_;
  249.         pos.node_->next_node = helper;
  250.     }
  251.    
  252.  
  253.     return Iterator{ pos.node_->next_node };
  254. }
  255.  
  256. private:
  257.     Node head_;
  258.     size_t size_ = 0;
  259. };
  260.  
  261. template <typename Type>
  262. void swap(SingleLinkedList<Type>& lhs, SingleLinkedList<Type>& rhs) noexcept {
  263.     lhs.swap(rhs);
  264. }
  265.  
  266. template <typename Type>
  267. bool operator==(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  268.     return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  269. }
  270.  
  271. template <typename Type>
  272. bool operator!=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  273.     return !(lhs == rhs);
  274. }
  275.  
  276. template <typename Type>
  277. bool operator<(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  278.     return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  279. }
  280.  
  281. template <typename Type>
  282. bool operator<=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  283.     return (lhs < rhs) || (lhs == rhs);
  284. }
  285.  
  286. template <typename Type>
  287. bool operator>(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  288.     return !(lhs < rhs);
  289. }
  290.  
  291. template <typename Type>
  292. bool operator>=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  293.     return (lhs > rhs) || (lhs == rhs);
  294. }
  295.  
  296. // Эта функция проверяет работу класса SingleLinkedList
  297. void Test4() {
  298.     struct DeletionSpy {
  299.         ~DeletionSpy() {
  300.             if (deletion_counter_ptr) {
  301.                 ++(*deletion_counter_ptr);
  302.             }
  303.         }
  304.         int* deletion_counter_ptr = nullptr;
  305.     };
  306.  
  307.     // Проверка PopFront
  308.     {
  309.         SingleLinkedList<int> numbers{ 3, 14, 15, 92, 6 };
  310.         numbers.PopFront();
  311.         assert((numbers == SingleLinkedList<int>{14, 15, 92, 6}));
  312.  
  313.         SingleLinkedList<DeletionSpy> list;
  314.         list.PushFront(DeletionSpy{});
  315.         int deletion_counter = 0;
  316.         list.begin()->deletion_counter_ptr = &deletion_counter;
  317.         assert(deletion_counter == 0);
  318.         list.PopFront();
  319.         assert(deletion_counter == 1);
  320.     }
  321.  
  322.     // Доступ к позиции, предшествующей begin
  323.     {
  324.         SingleLinkedList<int> empty_list;
  325.         const auto& const_empty_list = empty_list;
  326.         assert(empty_list.before_begin() == empty_list.cbefore_begin());
  327.         assert(++empty_list.before_begin() == empty_list.begin());
  328.         assert(++empty_list.cbefore_begin() == const_empty_list.begin());
  329.  
  330.         SingleLinkedList<int> numbers{ 1, 2, 3, 4 };
  331.         const auto& const_numbers = numbers;
  332.         assert(numbers.before_begin() == numbers.cbefore_begin());
  333.         assert(++numbers.before_begin() == numbers.begin());
  334.         assert(++numbers.cbefore_begin() == const_numbers.begin());
  335.     }
  336.  
  337.     // Вставка элемента после указанной позиции
  338.     {  // Вставка в пустой список
  339.         {
  340.             SingleLinkedList<int> lst;
  341.             const auto inserted_item_pos = lst.InsertAfter(lst.before_begin(), 123);
  342.             assert((lst == SingleLinkedList<int>{123}));
  343.             assert(inserted_item_pos == lst.begin());
  344.             assert(*inserted_item_pos == 123);
  345.         }
  346.  
  347.         // Вставка в непустой список
  348.         {
  349.             SingleLinkedList<int> lst{ 1, 2, 3 };
  350.             auto inserted_item_pos = lst.InsertAfter(lst.before_begin(), 123);
  351.  
  352.             assert(inserted_item_pos == lst.begin());
  353.             assert(inserted_item_pos != lst.end());
  354.             assert(*inserted_item_pos == 123);
  355.             assert((lst == SingleLinkedList<int>{123, 1, 2, 3}));
  356.  
  357.             inserted_item_pos = lst.InsertAfter(lst.begin(), 555);
  358.             assert(++SingleLinkedList<int>::Iterator(lst.begin()) == inserted_item_pos);
  359.             assert(*inserted_item_pos == 555);
  360.             assert((lst == SingleLinkedList<int>{123, 555, 1, 2, 3}));
  361.         };
  362.     }
  363.  
  364.     // Вспомогательный класс, бросающий исключение после создания N-копии
  365.     struct ThrowOnCopy {
  366.         ThrowOnCopy() = default;
  367.         explicit ThrowOnCopy(int& copy_counter) noexcept
  368.             : countdown_ptr(&copy_counter) {
  369.         }
  370.         ThrowOnCopy(const ThrowOnCopy& other)
  371.             : countdown_ptr(other.countdown_ptr)  //
  372.         {
  373.             if (countdown_ptr) {
  374.                 if (*countdown_ptr == 0) {
  375.                     throw std::bad_alloc();
  376.                 }
  377.                 else {
  378.                     --(*countdown_ptr);
  379.                 }
  380.             }
  381.         }
  382.         // Присваивание элементов этого типа не требуется
  383.         ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
  384.         // Адрес счётчика обратного отсчёта. Если не равен nullptr, то уменьшается при каждом копировании.
  385.         // Как только обнулится, конструктор копирования выбросит исключение
  386.         int* countdown_ptr = nullptr;
  387.     };
  388.  
  389.     // Проверка обеспечения строгой гарантии безопасности исключений
  390.     {
  391.         bool exception_was_thrown = false;
  392.         for (int max_copy_counter = 10; max_copy_counter >= 0; --max_copy_counter) {
  393.             SingleLinkedList<ThrowOnCopy> list{ ThrowOnCopy{}, ThrowOnCopy{}, ThrowOnCopy{} };
  394.             try {
  395.                 int copy_counter = max_copy_counter;
  396.                 list.InsertAfter(list.cbegin(), ThrowOnCopy(copy_counter));
  397.                 assert(list.GetSize() == 4u);
  398.             }
  399.             catch (const std::bad_alloc&) {
  400.                 exception_was_thrown = true;
  401.                 assert(list.GetSize() == 3u);
  402.                 break;
  403.             }
  404.         }
  405.         assert(exception_was_thrown);
  406.     }
  407.  
  408.     // Удаление элементов после указанной позиции
  409.     {
  410.         {
  411.             SingleLinkedList<int> lst{ 1, 2, 3, 4 };
  412.             const auto& const_lst = lst;
  413.             const auto item_after_erased = lst.EraseAfter(const_lst.cbefore_begin());
  414.             assert((lst == SingleLinkedList<int>{2, 3, 4}));
  415.             assert(item_after_erased == lst.begin());
  416.         }
  417.         {
  418.             SingleLinkedList<int> lst{ 1, 2, 3, 4 };
  419.             const auto item_after_erased = lst.EraseAfter(lst.cbegin());
  420.             assert((lst == SingleLinkedList<int>{1, 3, 4}));
  421.             assert(item_after_erased == (++lst.begin()));
  422.         }
  423.         {
  424.             SingleLinkedList<int> lst{ 1, 2, 3, 4 };
  425.             const auto item_after_erased = lst.EraseAfter(++(++lst.cbegin()));
  426.             assert((lst == SingleLinkedList<int>{1, 2, 3}));
  427.             assert(item_after_erased == lst.end());
  428.         }
  429.         {
  430.             SingleLinkedList<DeletionSpy> list{ DeletionSpy{}, DeletionSpy{}, DeletionSpy{} };
  431.             auto after_begin = ++list.begin();
  432.             int deletion_counter = 0;
  433.             after_begin->deletion_counter_ptr = &deletion_counter;
  434.             assert(deletion_counter == 0u);
  435.             list.EraseAfter(list.cbegin());
  436.             assert(deletion_counter == 1u);
  437.         }
  438.     }
  439. }
  440.  
  441. int main() {
  442.     Test4();
  443. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement