- Красно-черное дерево
- map, карта, словарь
- set, множество, упорядоченное множество
- multiset, мультимножество
Мною был реализован один из видов самобалансирующихся двоичных деревьев поиска - красно-черное дерево
Также были реализованы контейнеры стандартной библиотеки - map set multiset
Стиль кода в проекте - Google code style c++
пространоство имен (namespace) во всем проекте используется jokerooo7 namespace jokerooo7
Красно-черное дерево реализовано в ввиде класса RBTree, которые может представлено в виде одного шаблонного параметра:
#include "red_black_tree.h"
int main() {
jokerooo7::RBTree<int> my_class_one;
jokerooo7::RBTree<std::pair<int, bool>> my_class_two;
}Моя реализация не использует аллокаторов и компараторов:
template <typename K>
class RBtree {...}Красно-черное дерево представленно в виде файлов red_black_tree.h red_black_tree.tpp
Согласно правилу пяти c++, у меня реализовы все базовые конструкции. Дополнительно реализован конструктор с передачей в дерево данных по формату std::initializer_list<value_type>
RBTree() = default;
RBTree(std::initializer_list<value_type> const& items);
RBTree(const RBTree& other);
RBTree(RBTree&& other) noexcept;
~RBTree();
RBTree& operator=(const RBTree& other);
RBTree& operator=(RBTree&& other);Как и в стандартной библиотеке, у меня реализованы два метода - begin() и end().
begin() - возращает итератор который указывает на первоначальную ветку дерева (наименьшую).
end() - возращает итератор который указывает на пустой лист, следующий за самым наибольшим элементом(nullptr), при необбходимости можно вернуться на наибольший элоемент.
iterator begin() const;
iterator end() const;
// возращают неизменные итераторы
const_iterator cbegin() const;
const_iterator cend() const; typename jokerooo7::multiset<K>::iterator iter_one = my_class_one.begin();
++iter_one; // вернет следующий узел, по значению выше него
typename jokerooo7::multiset<K>::iterator iter_two = my_class_one.end();
--iter_two; // вернет самый наибольший элементРеализовал методы size() и max_size()
size() - возращает количество элементов в дереве
max_size() - использует клвсс std::allocator<value_type> для определения максимального размера контейнера
insert_many() - метод, который принимает большое количество аргументов и вставляет в контейнер и возращает вектор с парой итераторов и условным(bool) значением, вставился элемент или нет.
Использует внутри себя protected метод InsertInTree() для вставки элементов
Для того, чтобы два контейнера поменялись элементами - используется метож swap(RBTree &other), который принимает другой класс в качестве того, чтобы заменить два элемента.
merge(RBTree& other) - Используется для того, чтобы с другого контейнера принять все его элементы, без удаления элементов из другого.
Для удаления элемента используется метод erase(iterator any), который принимает итератор, который надо удалить с контейнера.
Для очистки всего контейнера используется метод clear()
Используется метод InsertInTree*(), в качестве аргументов функции он принимает значение, текущего типа в контейнере, и пару флагов (std::pair<bool, bool> mode). mode.first - Нужно ли переписовать уже существующие элементы, mode second - можно ли добавлять одинаковые элементы в конейнер.
Возращает он пару, итератор на вставленный элемент и его условное(bool) значение, был ли вставлен элемент или нет.
Реализован метод именованный Content() для проверки существет ли текущий элемент в контейнере ил нет.
Принимает он значение и ищет его в контейнере. C помощью private методов IsItMore() IsItLess() AreTheyEqual() сравнивает как просто элементы, так может сравнивать тип данных std::pait<AnyType, AnyType>.
Реализован вспомогательный метод, для проверки соответствуют ли два текущих контейнера друг дургу.
bool EqualityOfClasses(const RBTree& other)Используются для самобалансировки дерева в случаях удаления, вставки и провеки узлов дерева. Использовался алгоритм из wiki
RBTree содержит два внутренних класса, TreeIterator и TreeConstIterator.
Чтобы их вызов в производных классах соответствовал стандартной библиотеки, я использую алиасы iterator и const_iterator
Итераторы как и в стандартной библиотеки не защищены от обращения к удаленному узлу. За этим требуется следить самому.
int main() {
jokerooo7::RBTree<int> my_class_one;
typename jokerooo7::multiset<K>::iterator iter_one = my_class_one.begin();
}У класса итераторов реализованы операторы *, =, ++, --, !=, ==
typename jokerooo7::multiset<K>::iterator iter_one = my_class_one.begin()
*iter_one; // Вернет значение лежащее в этом итераторе
++iter_one; // Перейдет к следующему элементу и зафиксирует итератор на этом узле и вернет его
iter_one++; // Вернет копию текущего итератора, перейдет к следующему и зафиксируется на нем
iter_one != any_iterator; // Вернет булевое значение - несовпадают они или нет
iter_one == any_iterator; // Обратное !=
iter_one = any_iterator_or_node; // Присвоит к текущему итератору - другой итератор или узел дерева, также работает с std::move#include <сstddef> // Для работы с типом данных sizee_t
#include <utility> // Для работы с std::pair
#include <vector> // Для возврата вектоа со множеством вставок
#include <initializer_list> // Для вставки большого количества аргументовФайл с реализацией - "map.h"
Мой класс также, как и класс красно-черное дерево находиться в пространстве имен jokerooo7 и принимает два шаблонных аргумента - ключ и значение template <typename KT, typename T>
#include "red_black_tree.h"
namespace jokerooo7 {
template <typename KT, typename T>
class map : public RBTree<std::pair<KT, T> {...}
}Моя реализация STL библиотеки map использует уже написанное красно-черное дерево. Оно наследует все методы и с помощью конструкции using RBTree<std::pair<KT, T>>::RBTree; наследует абсолютно все конструкторы и декструкторы класса красно-черного дерева.
Алиасы совпадают со стандартной библиотекой и их можно видеть в файлах "map.h"
std::pair<iterator, bool> insert(const value_type& value) {
return this->InsertInTree(value, std::make_pair(false, false));
};
std::pair<iterator, bool> insert(const Key& key, const T& obj) {
value_type value = std::make_pair(key, obj);
return this->InsertInTree(value, std::make_pair(false, false));
};
std::pair<iterator, bool> insert_or_assign(const Key& key, const T& obj) {
value_type value = std::make_pair(key, obj);
return this->InsertInTree(value, std::make_pair(true, false));
};Эти три конструкции используют InsertInTree из RBTree, для вставки эементов и возращают тоже самое, что и InsertInTree()
- Первый метод - вставляет только значение, без ключа
- Второй метод - вставляет по ключу - значения, без переписывания значения
- Третий метод - вставляет с переписыванием значения по ключу
Метод contains() - реализует проверку наличия ключа в контейнере и возращает условное(bool) значение о его наличии или отсутсвтие
Функция contains() использует Сontent() для проверки содержимого.
Метод at() - реализует возврат неконстантной ссылки/или константного значения по ключу, если ключ не найден - выкидывает исключение. Использует Сontent()
Оператор [] - Возращает элемент по ключу и позволяет вставить элемент по ключу. Использует at()
Файл с реализацией - "set.h"
Мой класс также, как и класс красно-черное дерево находиться в пространстве имен jokerooo7 и принимает один шаблонный аргумента - значение template <typename T>
Моя реализация STL библиотеки [set](https://ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE_(%D1%82%D0%B8%D0%BF_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85) использует уже написанное красно-черное дерево. Оно наследует все методы и с помощью конструкции using RBTree<KT>::RBTree; наследует абсолютно все конструкторы и декструкторы класса красно-черного дерева.
Алиасы совпадают со стандартной библиотекой и их можно видеть в файлах "set.h"
std::pair<iterator, bool> insert(const value_type& value) {
return this->InsertInTree(value, std::make_pair(false, false));
};Вставка элемента value использует InsertInTree из RBTree, для вставки эементов и возращают тоже самое, что и InsertInTree()
contains() - такой же, как и у map, принимает значение, котороые в set является ключем
функция find() - возращает итератор на элемент, который использует Сontent() для проверки содержимого.
То же, что и set, но позволяет хранить повторяющиеся элементы.
Файл с реализацией - "multiset.h"
Многие методы RBTree - были переписаны, дополнены и изменена реализация, в связи с дополнением одинакового содержимого
Методы те же самые, что и multiset, дополнены некоторыми:
iterator lower_bound(const Key& key)- метод находит первый элемент не меньше заданногоiterator upper_bound(const Key& key)- метод который находит больше заданногоsize_type count(const Key& key) const- возращает количество данных ключей в контейнереstd::pair<iterator, iterator> equal_range(const Key& key)- возращает пару итераторов, где первый указывает на первый совпадающий ключ, а второй на следующий (больший по значению) за данным ключом;