Advertisement
force1987

list

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