shizaero

Untitled

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