Skip to content

Commit

Permalink
C++20 update on CMake | Added bubble class | new test cases
Browse files Browse the repository at this point in the history
Now bubble class is on it's first step, we have to make more of it though in the future as i explain in some comments(this could be a paper).
I fixed some issues with the avl class and added test cases for the new container
  • Loading branch information
spirosmaggioros committed Aug 17, 2024
1 parent e90f481 commit 4097918
Show file tree
Hide file tree
Showing 8 changed files with 326 additions and 13 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.12)
project(algoplus VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(EXCLUDE_DIR "third_party/")
set(unit_name "algoplus")
set(package_name "${unit_name}")
Expand Down Expand Up @@ -55,4 +55,4 @@ endif()

enable_testing()

add_subdirectory(tests)
add_subdirectory(tests)
25 changes: 15 additions & 10 deletions src/classes/tree/avl_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ template <typename T> class avl_tree {
* @param a the tree we want to copy
*/
explicit avl_tree(const avl_tree &a) : root(a.root), _size(a._size) {


}

/**
Expand Down Expand Up @@ -121,7 +121,7 @@ template <typename T> class avl_tree {
*@brief inorder function.
*@returns vector<T>, the elements inorder.
*/
std::vector<T> inorder() {
std::vector<T> inorder() const {
std::vector<T> path;
_inorder(
[&](std::shared_ptr<node> callbacked) {
Expand All @@ -134,7 +134,7 @@ template <typename T> class avl_tree {
@brief preorder function.
*@returns vector<T>, the elements preorder.
*/
std::vector<T> preorder() {
std::vector<T> preorder() const {
std::vector<T> path;
_preorder(
[&](std::shared_ptr<node> callbacked) {
Expand All @@ -147,7 +147,7 @@ template <typename T> class avl_tree {
*@brief postorder function.
*@returns vector<T>, the elements postorder.
*/
std::vector<T> postorder() {
std::vector<T> postorder() const {
std::vector<T> path;
_postorder(
[&](std::shared_ptr<node> callbacked) {
Expand Down Expand Up @@ -269,10 +269,15 @@ template <typename T> class avl_tree {
std::shared_ptr<node> nn = createNode(item);
if (root == nullptr)
return nn;
if (item < root->info)
if (item < root->info) {
root->left = _insert(root->left, item);
else
}
else if (item > root->info) {
root->right = _insert(root->right, item);
}
else {
return root;
}
int b = getBalance(root);
if (b > 1) {
if (getBalance(root->left) < 0)
Expand Down Expand Up @@ -325,7 +330,7 @@ template <typename T> class avl_tree {
}

void _inorder(std::function<void(std::shared_ptr<node>)> callback,
std::shared_ptr<node> root) {
std::shared_ptr<node> root) const {
if (root) {
_inorder(callback, root->left);
callback(root);
Expand All @@ -334,7 +339,7 @@ template <typename T> class avl_tree {
}

void _postorder(std::function<void(std::shared_ptr<node>)> callback,
std::shared_ptr<node> root) {
std::shared_ptr<node> root) const {
if (root) {
_inorder(callback, root->left);
_inorder(callback, root->right);
Expand All @@ -343,7 +348,7 @@ template <typename T> class avl_tree {
}

void _preorder(std::function<void(std::shared_ptr<node>)> callback,
std::shared_ptr<node> root) {
std::shared_ptr<node> root) const {
if (root) {
callback(root);
_inorder(callback, root->left);
Expand Down
8 changes: 8 additions & 0 deletions src/extra/.clangd
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,11 @@ If:

CompileFlags:
Add: [-std=c++20]

---

If:
PathMatch: .*\.h

CompileFlags:
Add: [-std=c++20]
13 changes: 13 additions & 0 deletions src/extra/containers/.clangd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
If:
PathMatch: .*\.cc

CompileFlags:
Add: [-std=c++23]

---

If:
PathMatch: .*\.h

CompileFlags:
Add: [-std=c++23]
209 changes: 209 additions & 0 deletions src/extra/containers/bubble.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**
* 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 <iostream>
#include <print>
#include <vector>
#include <optional>
#include <ranges>
#include <algorithm>
#include <utility>
#include <cassert>
#include "../../classes/tree/avl_tree.h"
#endif

template <typename T, size_t _SIZE>
class bubble {
private:
std::vector<std::pair<T, std::optional<avl_tree<T>>>> list;
size_t _size;

public:
explicit bubble() noexcept : _size(0) { }

template <size_t _NEW_SIZE>
bubble(const bubble<T, _NEW_SIZE> &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 <typename... Args>
void insert(Args&& ...keys);

template <typename... Args>
void remove(Args&& ...keys);

bool search(const T& key);

size_t size();

bool empty();

std::vector<T> 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, _SIZE> &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<T> tmp_tree(x.second.value());
std::vector<T> ino = tmp_tree.inorder();
for(size_t i = 0; i<ino.size(); i++){
if(i == ino.size() - 1) {
out << ino[i];
}
else{
out << ino[i] << " ";
}
}
out << "}" << '\n';
}
return out;
}
};

template <typename T, size_t _SIZE>
template <typename... Args>
inline void bubble<T, _SIZE>::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<T, std::optional<avl_tree<T>>> &a, const std::pair<T, std::optional<avl_tree<T>>> &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<T, std::optional<avl_tree<T>>> &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(idx - 1 < 0){
if(this->list[0].second == std::nullopt) {
this->list[0].second = avl_tree<T>();
}
this->list[0].second.value().insert(key);
}
else{
if(this->list[idx - 1].second == std::nullopt) {
this->list[idx - 1].second = avl_tree<T>();
}
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<T>();
}
this->list[this->list.size() - 1].second.value().insert(key);
}
_size++;
};
(std::invoke(_insert, std::forward<Args>(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 <typename T, size_t _SIZE>
template <typename... Args>
void bubble<T, _SIZE>::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, std::optional<avl_tree<T>>> &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<T, std::optional<avl_tree<T>>> &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].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<Args>(keys)), ...);
}

template <typename T, size_t _SIZE>
bool bubble<T, _SIZE>::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<T, std::optional<avl_tree<T>>> &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 <typename T, size_t _SIZE>
size_t bubble<T, _SIZE>::size() {
return this->_size;
}

template <typename T, size_t _SIZE>
bool bubble<T, _SIZE>::empty() {
return this->_size == 0;
}

#endif
7 changes: 7 additions & 0 deletions src/extra/table.h → src/extra/containers/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class table {

void pop_back();

bool empty();

std::vector<T> vectorize();

class Iterator;
Expand Down Expand Up @@ -191,6 +193,11 @@ void table<T>::pop_front() {
_check_update();
}

template <typename T>
bool table<T>::empty() {
return this->_size == 0;
}

template <typename T>
std::vector<T> table<T>::vectorize() {
if(this->root == nullptr) { return {}; }
Expand Down
Loading

0 comments on commit 4097918

Please sign in to comment.