Advertisement
chevengur

СПРИНТ № 7 | Односвязный список | Урок 4: Покоряем итераторы

May 5th, 2024
1,026
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.20 KB | None | 0 0
  1. #include <cassert>
  2. #include <cstddef>
  3. #include <string>
  4. #include <utility>
  5.  
  6. template <typename Type>
  7. class SingleLinkedList {
  8.     // Узел списка
  9.     struct Node {
  10.         Node() = default;
  11.         Node(const Type& val, Node* next)
  12.             : value(val)
  13.             , next_node(next) {
  14.         }
  15.         Type value;
  16.         Node* next_node = nullptr;
  17.     };
  18.  
  19.  
  20.     template <typename ValueType>
  21.     class BasicIterator {
  22.         // Класс списка объявляется дружественным, чтобы из методов списка
  23.         // был доступ к приватной области итератора
  24.         friend class SingleLinkedList;
  25.  
  26.         // Конвертирующий конструктор итератора из указателя на узел списка
  27.         explicit BasicIterator(Node* node): node_(node) {
  28.         }
  29.  
  30.     public:
  31.         // Объявленные ниже типы сообщают стандартной библиотеке о свойствах этого итератора
  32.  
  33.         // Категория итератора — forward iterator
  34.         // (итератор, который поддерживает операции инкремента и многократное разыменование)
  35.         using iterator_category = std::forward_iterator_tag;
  36.         // Тип элементов, по которым перемещается итератор
  37.         using value_type = Type;
  38.         // Тип, используемый для хранения смещения между итераторами
  39.         using difference_type = std::ptrdiff_t;
  40.         // Тип указателя на итерируемое значение
  41.         using pointer = ValueType*;
  42.         // Тип ссылки на итерируемое значение
  43.         using reference = ValueType&;
  44.  
  45.         BasicIterator() = default;
  46.  
  47.         BasicIterator(const BasicIterator<Type>& other) noexcept {
  48.             node_ = other.node_;
  49.         }
  50.  
  51.         BasicIterator& operator=(const BasicIterator& rhs) = default;
  52.  
  53.         [[nodiscard]] bool operator==(const BasicIterator<const Type>& rhs) const noexcept {
  54.             return ((rhs.node_ == nullptr && node_ == nullptr) || node_ == rhs.node_) ? true : false;
  55.         }
  56.  
  57.         [[nodiscard]] bool operator!=(const BasicIterator<const Type>& rhs) const noexcept {
  58.             return ((rhs.node_ == nullptr && node_ == nullptr) || node_ == rhs.node_) ? false : true;
  59.  
  60.         }
  61.  
  62.         [[nodiscard]] bool operator==(const BasicIterator<Type>& rhs) const noexcept {
  63.             return ((rhs.node_ == nullptr && node_ == nullptr) || node_ == rhs.node_) ? true : false;
  64.         }
  65.  
  66.         [[nodiscard]] bool operator!=(const BasicIterator<Type>& rhs) const noexcept {
  67.             return ((rhs.node_ == nullptr && node_ == nullptr) || node_ == rhs.node_) ? false : true;
  68.         }
  69.  
  70.         BasicIterator& operator++() noexcept {
  71.             node_ = node_->next_node;
  72.             return *this;
  73.         }
  74.  
  75.         BasicIterator operator++(int) noexcept {
  76.             auto old_value(*this);
  77.             ++(*this);
  78.             return old_value;
  79.         }
  80.  
  81.         [[nodiscard]] reference operator*() const noexcept {
  82.             return node_->value;
  83.         }
  84.  
  85.         [[nodiscard]] pointer operator->() const noexcept {
  86.             return &node_->value;
  87.         }
  88.  
  89.     private:
  90.         Node* node_ = nullptr;
  91.     };
  92.  
  93. public:
  94.  
  95.     using value_type = Type;
  96.     using reference = value_type&;
  97.     using const_reference = const value_type&;
  98.  
  99.     SingleLinkedList() : head_(), size_(0) {};
  100.  
  101.     ~SingleLinkedList() { Clear(); };
  102.  
  103.     void PushFront(const Type& value) {
  104.         head_.next_node = new Node(value, head_.next_node);
  105.         ++size_;
  106.     }
  107.  
  108.     void Clear() noexcept {
  109.         while (head_.next_node)
  110.         {
  111.             Node* new_node = head_.next_node->next_node;
  112.             delete head_.next_node;
  113.             head_.next_node = new_node;
  114.         }
  115.         size_ = 0;
  116.     }
  117.  
  118.     [[nodiscard]] size_t GetSize() const noexcept {
  119.         return size_;
  120.     }
  121.  
  122.     [[nodiscard]] bool IsEmpty() const noexcept {
  123.         return (size_ == 0) ? true : false;
  124.     }
  125.  
  126.     // Итератор, допускающий изменение элементов списка
  127.     using Iterator = BasicIterator<Type>;
  128.     // Константный итератор, предоставляющий доступ для чтения к элементам списка
  129.     using ConstIterator = BasicIterator<const Type>;
  130.  
  131.     [[nodiscard]] Iterator begin() noexcept {
  132.         return Iterator{ head_.next_node };
  133.     }
  134.  
  135.     [[nodiscard]] Iterator end() noexcept {
  136.         return Iterator{ nullptr };
  137.     }
  138.  
  139.     [[nodiscard]] ConstIterator begin() const noexcept {
  140.         return ConstIterator{ head_.next_node };
  141.     }
  142.  
  143.     [[nodiscard]] ConstIterator end() const noexcept {
  144.         return ConstIterator{ nullptr };
  145.     }
  146.  
  147.     [[nodiscard]] ConstIterator cbegin() const noexcept {
  148.         return ConstIterator{ head_.next_node };
  149.     }
  150.  
  151.     [[nodiscard]] ConstIterator cend() const noexcept {
  152.         return ConstIterator{ nullptr };
  153.     }
  154.  
  155. private:
  156.     Node head_;
  157.     size_t size_;
  158. };
  159.  
  160. // Эта функция тестирует работу SingleLinkedList
  161. void Test2() {
  162.     // Итерирование по пустому списку
  163.     {
  164.         SingleLinkedList<int> list;
  165.         // Константная ссылка для доступа к константным версиям begin()/end()
  166.         const auto& const_list = list;
  167.  
  168.         // Итераторы begin и end у пустого диапазона равны друг другу
  169.         assert(list.begin() == list.end());
  170.         assert(const_list.begin() == const_list.end());
  171.         assert(list.cbegin() == list.cend());
  172.         assert(list.cbegin() == const_list.begin());
  173.         assert(list.cend() == const_list.end());
  174.     }
  175.  
  176.     // Итерирование по непустому списку
  177.     {
  178.         SingleLinkedList<int> list;
  179.         const auto& const_list = list;
  180.  
  181.         list.PushFront(1);
  182.         assert(list.GetSize() == 1u);
  183.         assert(!list.IsEmpty());
  184.  
  185.         assert(const_list.begin() != const_list.end());
  186.         assert(const_list.cbegin() != const_list.cend());
  187.         assert(list.begin() != list.end());
  188.  
  189.         assert(const_list.begin() == const_list.cbegin());
  190.  
  191.         assert(*list.cbegin() == 1);
  192.         *list.begin() = -1;
  193.         assert(*list.cbegin() == -1);
  194.  
  195.         const auto old_begin = list.cbegin();
  196.         list.PushFront(2);
  197.         assert(list.GetSize() == 2);
  198.  
  199.         const auto new_begin = list.cbegin();
  200.         assert(new_begin != old_begin);
  201.         // Проверка прединкремента
  202.         {
  203.             auto new_begin_copy(new_begin);
  204.             assert((++(new_begin_copy)) == old_begin);
  205.         }
  206.         // Проверка постинкремента
  207.         {
  208.             auto new_begin_copy(new_begin);
  209.             assert(((new_begin_copy)++) == new_begin);
  210.             assert(new_begin_copy == old_begin);
  211.         }
  212.         // Итератор, указывающий на позицию после последнего элемента, равен итератору end()
  213.         {
  214.             auto old_begin_copy(old_begin);
  215.             assert((++old_begin_copy) == list.end());
  216.         }
  217.     }
  218.     // Преобразование итераторов
  219.     {
  220.         SingleLinkedList<int> list;
  221.         list.PushFront(1);
  222.         // Конструирование ConstIterator из Iterator
  223.         SingleLinkedList<int>::ConstIterator const_it(list.begin());
  224.         assert(const_it == list.cbegin());
  225.         assert(*const_it == *list.cbegin());
  226.  
  227.         SingleLinkedList<int>::ConstIterator const_it1;
  228.         // Присваивание ConstIterator'у значения Iterator
  229.         const_it1 = list.begin();
  230.         assert(const_it1 == const_it);
  231.     }
  232.     // Проверка оператора ->
  233.     {
  234.         using namespace std;
  235.         SingleLinkedList<std::string> string_list;
  236.  
  237.         string_list.PushFront("one"s);
  238.         assert(string_list.cbegin()->length() == 3u);
  239.         string_list.begin()->push_back('!');
  240.         assert(*string_list.begin() == "one!"s);
  241.     }
  242. }
  243.  
  244. int main() {
  245.     Test2();
  246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement