Advertisement
paranid5

Array

Jul 18th, 2020
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.45 KB | None | 0 0
  1. #ifndef ARRAY_H
  2. #define ARRAY_H
  3.  
  4. #include <cstdlib>
  5. #include <stdexcept>
  6. #include <algorithm>
  7. #include <functional>
  8.  
  9. template<typename T>
  10. class Array
  11. {
  12. public:
  13.  
  14.     Array(const size_t, const T&);
  15.  
  16.     ~Array();
  17.  
  18.     size_t size() const;
  19.  
  20.     bool empty() const;
  21.  
  22.     T& get(size_t) const;
  23.  
  24.     T& operator[] (size_t) const;
  25.  
  26.     void push(const T&);
  27.  
  28.     T& pop();
  29.  
  30.     T& back() const;
  31.  
  32.     void insert(size_t, const T&);
  33.  
  34.     void unsafe_insert(size_t, const T&);
  35.  
  36.     T& erase(size_t);
  37.  
  38.     T& unsafe_erase(size_t);
  39.  
  40.     void clear();
  41.  
  42.     void sort();
  43.  
  44.     void sort_by(std::function<bool(const T&, const T&)>);
  45.  
  46.     bool is_sorted();
  47.  
  48.     size_t find(const T&) const;
  49.  
  50.     void resize(size_t, const T&);
  51.  
  52.     void unsafe_resize(size_t);
  53.  
  54. private:
  55.  
  56.     T* container_;
  57.     size_t size_;
  58.     bool sort_status_;
  59.    
  60. };
  61.  
  62.  
  63.  
  64. /**
  65.  * Конструктор класса Array
  66.  * Параметры:
  67.  * @param size_ - текущий размер массива;
  68.  * @param container_ - содержимое массива
  69.  * @param sort_status_ - проверка массива на отсортированность
  70.  * Весь Array инициализируется elem
  71.  * Т.к. при выделении памяти под Array может возникнуть ошибка,
  72.  * мы это проверяем
  73.  */
  74.  
  75. template <typename T>
  76. Array<T>::Array(const size_t len, const T& elem)
  77. {
  78.     size_ = len;
  79.     container_ = static_cast<T*>(malloc(size_ * sizeof(T)));
  80.     if (container_ == nullptr) throw std::runtime_error("memory allocation error");
  81.     for (size_t i = 0; i < size_; i++) container_[i] = elem;
  82.     sort_status_ = true;
  83. }
  84.  
  85. /**
  86.  *Деструктор для Array
  87.  */
  88.  
  89. template<typename T>
  90. Array<T>::~Array()
  91. {
  92.     free(container_);
  93. }
  94.  
  95. /**
  96.  * @return размер массива
  97.  */
  98.  
  99. template<typename T>
  100. size_t Array<T>::size() const
  101. {
  102.     const size_t len = size_;
  103.     return len;
  104. }
  105.  
  106. /**
  107.  * Метод empty() проверяет Array на пустоту
  108.  * @return размер > 0 ?
  109.  */
  110.  
  111. template<typename T>
  112. bool Array<T>::empty() const
  113. {
  114.     return size_ > 0;
  115. }
  116.  
  117. /**
  118.  * Метод push() добавляет @param value в конец
  119.  * Т.к. функция realloc() может вернуть нулевой указатель
  120.  * в случае неудачного перевыделения памяти,
  121.  * мы делаем проверку на нулевой указатель
  122.  * Так же осуществляется проверка на отсортированность
  123.  */
  124.  
  125. template<typename T>
  126. void Array<T>::push(const T& value)
  127. {
  128.     container_ = static_cast<T*>(realloc(container_, (++size_) * sizeof(T)));
  129.     if (container_ == nullptr) throw std::runtime_error("memory reallocation error");
  130.     container_[size_ - 1] = value;
  131.     if (size_ == 1 || container_[size_ - 2] <= container_[size_ - 1]) sort_status_ = true;
  132.     else sort_status_ = false;
  133. }
  134.  
  135. /**
  136.  * Метод pop() удаляет последний элемент Array.
  137.  * Т.к. Array может быть пустым, мы проверяем его на пустоту.
  138.  * Если массив пуст, то ошибка.
  139.  * Т.к. функция realloc() может вернуть нулевой указатель
  140.  * в случае неудачного перевыделения памяти,
  141.  * мы делаем проверку на нулевой указатель.
  142.  * @return удаленный элемент
  143.  */
  144.  
  145. template<typename T>
  146. T& Array<T>::pop()
  147. {
  148.     if (size_ == 0) throw std::out_of_range("array is empty");
  149.     const T end = container_[size_ - 1];
  150.     container_ = static_cast<T*>(realloc(container_, (--size_) * sizeof(T)));
  151.     if (container_ == nullptr) throw std::runtime_error("memory reallocation error");
  152.     return end;
  153. }
  154.  
  155. /**
  156.  * @return последний элемент Array,
  157.  * если тот не пуст, иначе сообщает об ошибке
  158.  */
  159.  
  160. template<typename T>
  161. T& Array<T>::back() const
  162. {
  163.     if (size_ == 0) throw std::out_of_range("array is empty");
  164.     else return container_[size_ - 1];
  165. }
  166.  
  167. /**
  168.  * Метод insert() добавляет @param value на место @param index.
  169.  * index может выходить за пределы массива,
  170.  * поэтому мы делаем проверку.
  171.  * Т.к. функция realloc() может вернуть нулевой указатель
  172.  * в случае неудачного перевыделения памяти,
  173.  * мы делаем проверку на нулевой указатель.
  174.  * Статуc отсортированности так же проверяется
  175.  */
  176.  
  177. template<typename T>
  178. void Array<T>::insert(const size_t index, const T& value)
  179. {
  180.     container_ = static_cast<T*>(realloc(container_, (++size_) * sizeof(T)));
  181.     if (container_ == nullptr) throw std::runtime_error("memory reallocation error");
  182.     if (index >= size_) throw std::out_of_range("index out of range");
  183.     container_[size_ - 1] = value;
  184.     for (size_t i = size_ - 1; i > index; i--) std::swap(container_[i], container_[i - 1]);
  185.     if (sort_status_)
  186.     {
  187.         if (index >= 0 && index < size_ - 1) // 2 соседа
  188.         {
  189.             if (container_[index] >= container_[index - 1] && container_[index] <= container_[index + 1]) sort_status_ = true;
  190.             else sort_status_ = false;
  191.         }
  192.         else if (index == size_ - 1) // последний
  193.         {
  194.             if (container_[index] >= container_[index - 1]) sort_status_ = true;
  195.             else sort_status_ = false;
  196.         }
  197.         else // первый
  198.         {
  199.             if (container_[index] <= container_[index + 1]) sort_status_ = true;
  200.             else sort_status_ = false;
  201.         }
  202.     }
  203.     else is_sorted();
  204. }
  205.  
  206. /**
  207.  *  ___________________
  208.  * |                   |
  209.  * | НЕБЕЗОПАСНЫЙ КОД  |
  210.  * |___________________|
  211.  *
  212.  * Метод добавляет на место @param index
  213.  * значение @param value.
  214.  * Никаких проверок, в том числе на отсортированность не выполняется.
  215.  * Не рекомендуется использовать в безопасном коде
  216.  */
  217.  
  218. template<typename T>
  219. void Array<T>::unsafe_insert(const size_t index, const T& value)
  220. {
  221.     container_ = static_cast<T*>(realloc(container_, (++size_) * sizeof(T)));
  222.     container_[size_ - 1] = value;
  223.     for (size_t i = size_ - 1; i > index; i--) std::swap(container_[i], container_[i - 1]);
  224. }
  225.  
  226. /**
  227.  * Метод erase() удаляет элемент по @param index.
  228.  * index может выходить за пределы массива,
  229.  * поэтому мы делаем проверку.
  230.  * Т.к. функция realloc() может вернуть нулевой указатель
  231.  * в случае неудачного перевыделения памяти,
  232.  * мы делаем проверку на нулевой указатель.
  233.  * @return удалённый элемент
  234.  */
  235.  
  236. template<typename T>
  237. T& Array<T>::erase(const size_t index)
  238. {
  239.     if (index >= size_) throw std::out_of_range("index out of range");
  240.     const T elem = container_[index];
  241.     for (size_t i = index; i < size_ - 1; i++) std::swap(container_[i], container_[i + 1]);
  242.     container_ = static_cast<T*>(realloc(container_, (--size_) * sizeof(T)));
  243.     if (container_ == nullptr) throw std::runtime_error("memory reallocation error");
  244.     is_sorted();
  245.     return elem;
  246. }
  247.  
  248. /**
  249.  *  ___________________
  250.  * |                   |
  251.  * | НЕБЕЗОПАСНЫЙ КОД  |
  252.  * |___________________|
  253.  *
  254.  * Метод удаляет элемент по @param index.
  255.  * Не рекомендуется использовать в безопасном коде
  256.  * @return удалённый элемент
  257.  */
  258.  
  259. template<typename T>
  260. T& Array<T>::unsafe_erase(const size_t index)
  261. {
  262.     const T elem = container_[index];
  263.     for (size_t i = index; i < size_ - 1; i++) std::swap(container_[i], container_[i + 1]);
  264.     container_ = static_cast<T*>(realloc(container_, (--size_) * sizeof(T)));
  265.     return elem;
  266. }
  267.  
  268. /*
  269.  * Метод clear() очищает Array
  270.  * И меняет значения
  271.  * size_ на ноль и sort_status_ на true
  272.  */
  273.  
  274. template<typename T>
  275. void Array<T>::clear()
  276. {
  277.     size_ = 0;
  278.     container_ = static_cast<T*>(realloc(container_, 0));
  279.     if (container_ == nullptr) throw std::runtime_error("memory reallocation error");
  280.     sort_status_ = true;
  281. }
  282.  
  283. /*
  284.  * Сортировка Array
  285.  */
  286.  
  287. template<typename T>
  288. void Array<T>::sort()
  289. {
  290.     if (sort_status_) return;
  291.     std::sort(container_, container_ + size_);
  292.     sort_status_ = true;
  293. }
  294.  
  295. /**
  296.  * !!! ДЛЯ ПРОДВИНУТЫХ ПОЛЬЗОВАТЕЛЕЙ !!!
  297.  *
  298.  * @param your_function - пользовательская функция для сортировки.
  299.  * Функция задаётся как функция сравнения для std::sort,
  300.  *
  301.  * которая возвращает:
  302.  * @return 1, когда arg1 > arg2
  303.  * @return 0, когда arg1 == arg2
  304.  * @return -1, когда arg1 < arg2
  305.  *
  306.  * И имеет параметры:
  307.  * @param const void*
  308.  * @param const void*
  309.  */
  310.  
  311. template<typename T>
  312. void Array<T>::sort_by(std::function<bool(const T&, const T&)> your_function)
  313. {
  314.     if (sort_status_) return;
  315.     std::sort(container_, container_ + size_, your_function);
  316.     sort_status_ = true;
  317. }
  318.  
  319. /*
  320.  * Поверка на отсортированность массива.
  321.  * Если массив до этого был отсортированн,
  322.  * то проверки не будет,
  323.  * иначе будет тотальная проверка за O(n)
  324.  */
  325.  
  326. template<typename T>
  327. bool Array<T>::is_sorted()
  328. {
  329.     if (!sort_status_)
  330.     {
  331.         for (size_t i = 0; i < size_ - 1; i++)
  332.         {
  333.             if (container_[i] > container_[i + 1])
  334.             {
  335.                 sort_status_ = false;
  336.                 return false;
  337.             }
  338.         }
  339.         sort_status_ = true;
  340.         return true;
  341.     }
  342.     return true;
  343. }
  344.  
  345. /**
  346.  * Метод find() ищет @param value в Array
  347.  * Если нашли значение, то @return индекс
  348.  * Иначе @return размер массива + 1
  349.  */
  350.  
  351. template<typename T>
  352. size_t Array<T>::find(const T& value) const
  353. {
  354.     return std::find(container_, container_ + size_, value);
  355. }
  356.  
  357. /**
  358.  * Метод resize() изменяет размер Array на @param new_size
  359.  * Если новый размер больше предыдущего,
  360.  * то новые элементы инициализируются
  361.  * @param elem, иначе удаляются
  362.  * Также осуществляется проверка на отсортированность
  363.  */
  364.  
  365. template<typename T>
  366. void Array<T>::resize(const size_t new_size, const T& elem)
  367. {
  368.     container_ = static_cast<T*>(realloc(container_, new_size * sizeof(T)));
  369.     if (container_ == nullptr) throw std::runtime_error("memory reallocation error");
  370.     if (new_size > size_) for (size_t i = size_; i < new_size; i++) container_[i] = elem;
  371.     if (new_size > size_)
  372.     {
  373.         if (elem >= container_[size_ - 1]) sort_status_ = true;
  374.         else sort_status_ = false;
  375.     }
  376.     size_ = new_size;
  377. }
  378.  
  379. /**
  380.  *  ___________________
  381.  * |                   |
  382.  * | НЕБЕЗОПАСНЫЙ КОД  |
  383.  * |___________________|
  384.  *
  385.  * Метод unsafe_resize() изменяет размер Array на @param new_size
  386.  * Методом не рекомендуется пользоваться в безопасном коде,
  387.  * т.к. при увеличении размера, новые элементы
  388.  * становятся неинициализированными,
  389.  * а статус сортировки не проверяется
  390.  */
  391.  
  392. template<typename T>
  393. void Array<T>::unsafe_resize(const size_t new_size)
  394. {
  395.     container_ = static_cast<T*>(realloc(container_, new_size * sizeof(T)));
  396.     if (container_ == nullptr) throw std::runtime_error("memory reallocation error");
  397.     size_ = new_size;
  398. }
  399.  
  400. /**
  401.  * Метод get() возвращает ссылку на элемент
  402.  * массива по @param index.
  403.  * Т.к. index может выходить за пределы массива,
  404.  * мы проверяем это
  405.  */
  406.  
  407. template<typename T>
  408. T& Array<T>::get(const size_t index) const
  409. {
  410.     if (index >= size_) throw std::out_of_range("index out of range");
  411.     return container_[index];
  412. }
  413.  
  414. /*
  415.  * Оператор [] делает всё то, что и метод get()
  416.  */
  417.  
  418. template<typename T>
  419. T& Array<T>::operator[](const size_t index) const
  420. {
  421.     return get(index);
  422. }
  423.  
  424. #endif // ARRAY_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement