diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..5646ba60 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/extra/containers/bubble"] + path = src/extra/containers/bubble + url = https://github.com/spirosmaggioros/bubble diff --git a/src/extra/containers/bubble b/src/extra/containers/bubble new file mode 160000 index 00000000..0ac5cabf --- /dev/null +++ b/src/extra/containers/bubble @@ -0,0 +1 @@ +Subproject commit 0ac5cabf1933b9bc5c3073ad8beb0fb50a625599 diff --git a/src/extra/containers/bubble.h b/src/extra/containers/bubble.h deleted file mode 100644 index d618a63f..00000000 --- a/src/extra/containers/bubble.h +++ /dev/null @@ -1,221 +0,0 @@ -/** -* This is the bubble data structure, we highly suggest to initialize it with a various range of elements -* like {-500, -100, 0, 100, 500}(for _SIZE=5) if you want to use elements from [-500, 500]. In the future, we will -* work on making it more generic and make the list change, for example, if the user give {-2, -1, 0, 1, 2} and always -* insert keys with value > 2, then bubble will not work efficiently, so this has to change in the future -*/ - -#ifndef BUBBLE_H -#define BUBBLE_H - -#ifdef __cplusplus -#include -#include -#include -#include -#include -#include -#include -#include "../../classes/tree/avl_tree.h" -#endif - -template -class bubble { -private: - std::vector>>> list; - size_t _size; - -public: - explicit bubble() noexcept : _size(0) { } - - template - bubble(const bubble &t) noexcept : _size(t._size) { - try { - if(_NEW_SIZE != _SIZE) { throw std::logic_error("Tried to copy bubbles with different sizes"); } - this->list = t.list; - } - catch (std::logic_error &e){ - std::cerr << e.what() << '\n'; - } - } - - template - void insert(Args ...keys); - - template - void remove(Args ...keys); - - bool search(const T& key); - - size_t size(); - - bool empty(); - - std::vector operator[] (const size_t& index) const { - assert(index < this->_size && index >= 0); - if(this->list[index].second == std::nullopt) { return {this->list[index].first}; } - return this->list[index].second.value().inorder(); - } - - friend std::ostream & operator << (std::ostream &out, const bubble &t){ - if(t._size == 0) { return out; } - for(auto && x : t.list) { - out << x.first << ": {"; - if(x.second == std::nullopt){ - out << "}" << '\n'; - continue; - } - avl_tree tmp_tree(x.second.value()); - std::vector ino = tmp_tree.inorder(); - for(size_t i = 0; i -template -inline void bubble::insert(Args ...keys) { - auto _insert = [&](const T&& key) -> void { - if(_size < _SIZE) { - list.push_back({key, std::nullopt}); - _size++; - return; - } - if(_size == _SIZE) { - std::ranges::sort(list, [](const std::pair>> &a, const std::pair>> &b){ - return a.first < b.first; - }); - } - - auto it = std::lower_bound(std::ranges::begin(this->list), std::ranges::end(this->list), key, [](const std::pair>> &pair, const T &key){ return pair.first < key; }); - - if(it != std::ranges::end(this->list)) { - int idx = std::distance(std::ranges::begin(this->list), it); - if(this->list[idx].first == key) { return; } - - if(idx - 1 < 0){ - if(this->list[0].second == std::nullopt) { - this->list[0].second = avl_tree(); - } - // if(this->list[0].first == key) { return; } I think we don't need this - this->list[0].second.value().insert(key); - } - else{ - if(this->list[idx - 1].second == std::nullopt) { - this->list[idx - 1].second = avl_tree(); - } - // if(this->list[idx].first == key) { return; } - this->list[idx - 1].second.value().insert(key); - } - } - else { - if(this->list[this->list.size() - 1].second == std::nullopt){ - this->list[this->list.size() - 1].second = avl_tree(); - } - // if(this->list[this->list.size() - 1].first == key) { return; } - this->list[this->list.size() - 1].second.value().insert(key); - } - _size++; - }; - (std::invoke(_insert, std::forward(keys)), ...); -} - - -/** -* For now remove function can't remove key elements that exist on the list -* It can only remove them if none of the nodes have a tree yet. -* We have to find a way to make the tree rebalance itself and the root of the tree come on top -* after a removal of a key element -*/ -template -template -void bubble::remove(Args ...keys) { - auto _remove = [&](const T&& key) -> void{ - if(this->_size == 0) { return; } - if(this->_size <= _SIZE) { - auto [begin, end] = std::ranges::remove_if(this->list, [&](const std::pair>> &t) { return t.first == key; }); - list.erase(begin, end); - _size--; - } - else{ - auto it = std::lower_bound(std::ranges::begin(this->list), std::ranges::end(this->list), key, [](const std::pair>> &pair, const T &key){ return pair.first < key; }); - if(it != std::ranges::end(this->list)) { - size_t idx = std::ranges::distance(std::ranges::begin(this->list), it); - - if(this->list[idx].first == key && this->list[idx].second != std::nullopt) { - T curr_root = this->list[idx].second.value().get_root(); - this->list[idx].second.value().remove(curr_root); - this->list[idx].first = curr_root; - return; - } - - if(idx - 1 < 0){ - if(this->list[0].second == std::nullopt){ - return; - } - this->list[0].second.value().remove(key); - } - else{ - if(this->list[idx - 1].second == std::nullopt) { - return; - } - this->list[idx - 1].second.value().remove(key); - } - } - else { - if(this->list[this->list.size() - 1].second == std::nullopt) { - return; - } - this->list[this->list.size() - 1].second.value().remove(key); - } - _size--; - } - }; - (std::invoke(_remove, std::forward(keys)), ...); -} - -template -bool bubble::search(const T& key) { - if(this->_size == 0) { return false; } - auto it = std::lower_bound(std::ranges::begin(this->list), std::ranges::end(this->list), key, [](const std::pair>> &pair, const T &key){ return pair.first < key; }); - if (it != std::ranges::end(this->list)){ - size_t idx = std::ranges::distance(std::ranges::begin(this->list), it); - if(idx - 1 < 0){ - if(this->list[0].first == key) { return true; } - if(this->list[0].second == std::nullopt) { return false; } - if(this->list[0].second.value().search(key) == true) { return true; } - } - else { - if(this->list[idx].first == key) { return true; } - if(this->list[idx - 1].second == std::nullopt) { return false; } - if(this->list[idx - 1].second.value().search(key) == true) { return true; } - } - } - else { - if(this->list[this->list.size() - 1].first == key) { return true; } - if(this->list[this->list.size() - 1].second == std::nullopt) { return false; } - if(this->list[this->list.size() - 1].second.value().search(key) == true) { return true; } - } - return false; -} - -template -size_t bubble::size() { - return this->_size; -} - -template -bool bubble::empty() { - return this->_size == 0; -} - -#endif diff --git a/src/extra/tests/bubble.cc b/src/extra/tests/bubble.cc deleted file mode 100644 index 9bbd1d68..00000000 --- a/src/extra/tests/bubble.cc +++ /dev/null @@ -1,94 +0,0 @@ -#define CATCH_CONFIG_MAIN -#include "../../../third_party/catch.hpp" -#include "../containers/bubble.h" -#include -#include - -TEST_CASE("Testing insertion for bubble class") { - bubble b; - b.insert(-10, 0, 10, 40, 50); - REQUIRE(b.size() == 5); - REQUIRE(b[0][0] == -10); - REQUIRE(b[1][0] == 0); - REQUIRE(b[2][0] == 10); - REQUIRE(b[3][0] == 40); - REQUIRE(b[4][0] == 50); -} - -TEST_CASE("Testing searching for bubble class") { - bubble b; - - b.insert("a", "c", "i", "l", "y"); - b.insert("because", "bee", "before"); - b.insert("careful", "coconut", "circle"); - b.insert("ker"); - b.insert("normal", "normalize"); - b.insert("wow"); - REQUIRE(b.search("wow") == true); - REQUIRE(b.search("coconut") == true); - REQUIRE(b.search("a") == true); - REQUIRE(b.search("before") == true); - b.remove("wow"); - REQUIRE(b.search("wow") == false); - b.remove("before"); - REQUIRE(b.search("before") == false); - b.remove("c"); - REQUIRE(b.search("c") == false); -} - -TEST_CASE("Testing removing for bubble class") { - bubble b; - b.insert('a', 'd', 'h', 'k', 'w'); - REQUIRE(b.search('h') == true); - b.remove('h'); - REQUIRE(b.search('h') == false); - b.insert('g'); - b.insert('s'); - b.insert('p'); - b.insert('o'); - REQUIRE(b.search('s') == true); - b.remove('s'); - REQUIRE(b.search('s') == false); - - bubble b2; - b2.insert(-50, -20, 0, 20, 50); - b2.insert(35, 30, 38, 36, 45, 22); - b2.remove(20); - std::vector v { b2[3] }; - std::vector check {22, 30, 36, 38, 45}; - REQUIRE(v == check); - b2.remove(35); - v = b2[3]; - check = {22, 30, 38, 45}; - REQUIRE(v == check); -} - -TEST_CASE("Testing size for bubble class") { - bubble b; - b.insert(1, 2, 3, 4, 5, 6, 7, 8); - REQUIRE(b.size() == 8); - b.remove(1); - b.remove(2); - REQUIRE(b.size() == 6); - b.remove(3, 4, 5, 6, 7, 8); - REQUIRE(b.size() == 0); -} - -TEST_CASE("Testing empty for bubble class") { - bubble b; - REQUIRE(b.empty() == true); - b.insert(10, 20, 30, 40, 50); - REQUIRE(b.empty() == false); - b.remove(10, 20, 30, 40, 50); - REQUIRE(b.empty() == true); -} - -TEST_CASE("Testing operator << for bubble class") { - bubble b; - b.insert(10, 20, 30, 40, 50, 60, 15, 25, 35, 45); - CHECK_NOTHROW(std::cout << b << '\n'); - - bubble b2; - b2.insert("hello there", "we", "are", "csrt team", "yay!!"); - CHECK_NOTHROW(std::cout << b2 << '\n'); -}