Skip to content

Commit

Permalink
added interval tree class & tests
Browse files Browse the repository at this point in the history
  • Loading branch information
spirosmaggioros committed Jan 28, 2024
1 parent 1df011f commit b1048f4
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 10 deletions.
21 changes: 21 additions & 0 deletions examples/tree/interval_tree.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifdef __cplusplus
#include "../../src/classes/tree/interval_tree.h"
#include <iostream>
#endif

int main() {
interval_tree<int> i;
i.insert({20, 36});
i.insert({3, 41});
i.insert({29, 99});
i.insert({0, 1});
i.insert({10, 15});

// you can visualize the tree
i.visualize();

// you can get the elements in any order
std::vector<std::pair<int, int>> __preorder = i.preorder();
std::vector<std::pair<int, int>> __inorder = i.inorder();
// ....
}
10 changes: 4 additions & 6 deletions examples/tree/unnamed.dot
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
digraph Tree {
a->t
t->f
f->p
p->o
o->m
t->w
"20,36"->"3,41"
"3,41"->"0,1"
"3,41"->"10,15"
"20,36"->"29,99"
}
8 changes: 4 additions & 4 deletions src/classes/tree/bst.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,17 @@ template <typename T> class bst {

void __postorder(std::function<void(node *)> callback, node *root) {
if (root) {
__inorder(callback, root->left);
__inorder(callback, root->right);
__postorder(callback, root->left);
__postorder(callback, root->right);
callback(root);
}
}

void __preorder(std::function<void(node *)> callback, node *root) {
if (root) {
callback(root);
__inorder(callback, root->left);
__inorder(callback, root->right);
__preorder(callback, root->left);
__preorder(callback, root->right);
}
}

Expand Down
294 changes: 294 additions & 0 deletions src/classes/tree/interval_tree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
#ifndef INTERVAL_TREE_H
#define INTERVAL_TREE_H

#include <memory>
#ifdef __cplusplus
#include "../../visualization/tree_visual/tree_visualization.h"
#include <iostream>
#endif

/*
*interval tree class
*/
template <typename T> class interval_tree {
public:
interval_tree(std::vector<std::pair<T, T>> v = {}) {
if (!v.empty()) {
for (auto &x : v) {
this->insert({x.first, x.second});
}
}
}

/*
*insert function.
8@param p: interval to be inserted.
*/
void insert(std::pair<T, T> p) {
interval i = interval(p);
root = __insert(root, i);
}

/*
*remove function.
*@param p: interval to be removed.
*/
void remove(std::pair<T, T> p) {
interval i = interval(p);
root = __remove(root, i);
}

/*
*overlap function.
*@param p1: first interval.
*@param p2: second interval.
*Returns true if p1 overlaps p2.
*/
bool overlap(std::pair<T, T> p1, std::pair<T, T> p2) {
interval i1 = interval(p1), i2 = interval(p2);
return i1.high >= i2.low && i1.low <= i2.high;
}

/*
*inorder function.
*Returns vector<pair<T,T>>, the elements inorder.
*/
std::vector<std::pair<T, T>> inorder() {
std::vector<std::pair<T, T>> path;
__inorder(
[&](std::shared_ptr<node> callbacked) {
path.push_back({callbacked->i->low, callbacked->i->high});
},
root);
return path;
}

/*
*preorder function.
*Returns vector<pair<T,T>>, the elements preorder.
*/
std::vector<std::pair<T, T>> preorder() {
std::vector<std::pair<T, T>> path;
__preorder(
[&](std::shared_ptr<node> callbacked) {
path.push_back({callbacked->i->low, callbacked->i->high});
},
root);
return path;
}

/*
*postorder function.
*Returns vector<pair<T, T>>, the elements postorder.
*/
std::vector<std::pair<T, T>> postorder() {
std::vector<std::pair<T, T>> path;
__postorder(
[&](std::shared_ptr<node> callbacked) {
path.push_back({callbacked->i->low, callbacked->i->high});
},
root);
return path;
}

void visualize() {
std::string __generated = generate_visualization();
visualization::visualize(__generated);
}

/*
*<< operator for interval_tree class.
*/
friend std::ostream &operator<<(std::ostream &out, interval_tree<T> &t) {
if (!t.root) {
out << "";
return out;
}
out << '"';
std::vector<std::pair<T, T>> __inorder = t.inorder();
for (auto &x : __inorder) {
out << '"' << x.first << ' ' << x.second << '"' << " ";
}
out << '"';
return out;
}

private:
struct interval {
T low;
T high;
interval(std::pair<T, T> p)
: low(std::min(p.first, p.second)), high(std::max(p.first, p.second)) {}
};
struct node {
interval *i;
int max;
std::shared_ptr<node> right;
std::shared_ptr<node> left;
node(interval n)
: i(new interval(n)), max(n.high), right(nullptr), left(nullptr) {}
};
std::shared_ptr<node> root;

std::shared_ptr<node> new_node(interval i) {
std::shared_ptr<node> p = std::make_shared<node>(i);
return p;
}

/*
*helper function for insertion
*/
std::shared_ptr<node> __insert(std::shared_ptr<node> root, interval i) {
if (!root) {
return new_node(i);
}
T l = root->i->low;
if (i.low < l) {
root->left = __insert(root->left, i);
} else {
root->right = __insert(root->right, i);
}
if (root->max < i.high) {
root->max = i.high;
}
return root;
}

/*
*helper function for remove.
*/
std::shared_ptr<node> __remove(std::shared_ptr<node> root, interval i) {
if (!root) {
return nullptr;
}
std::shared_ptr<node> p = root;
while (p) {
if (p->i->low > i.low) {
p = p->left;
} else if (p->i->low < i.low) {
p = p->right;
} else {
if (!p->right && !p->left) {
return nullptr;
} else if (p->right && !p->left) {
std::shared_ptr<node> temp = root->right;
return temp;
} else if (p->left && !p->right) {
std::shared_ptr<node> temp = p->left;
return temp;
} else {
std::shared_ptr<node> temp = root;
while (temp && temp->left) {
temp = temp->left;
}
p->i = temp->i;
p->max = temp->max;
p->right = __remove(p->right, *temp->i);
}
}
}
return root;
}

void __inorder(std::function<void(std::shared_ptr<node>)> callback,
std::shared_ptr<node> root) {
if (root) {
__inorder(callback, root->left);
callback(root);
__inorder(callback, root->right);
}
}

void __postorder(std::function<void(std::shared_ptr<node>)> callback,
std::shared_ptr<node> root) {
if (root) {
__postorder(callback, root->left);
__postorder(callback, root->right);
callback(root);
}
}

void __preorder(std::function<void(std::shared_ptr<node>)> callback,
std::shared_ptr<node> root) {
if (root) {
callback(root);
__preorder(callback, root->left);
__preorder(callback, root->right);
}
}

std::string generate_visualization() {
std::string __generate = __inorder_gen(root);
return __generate;
}

std::string __inorder_gen(std::shared_ptr<node> root) {
std::string __s;
if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
if (root->left) {
__s += '"';
__s += root->i->low;
__s += ',';
__s += root->i->high;
__s += '"';
__s += "->";
__s += '"';
__s += root->left->i->low;
__s += ',';
__s += root->left->i->high;
__s += '"';
__s += "\n";
__s += __inorder_gen(root->left);
}
if (root->right) {
__s += '"';
__s += root->i->low;
__s += ',';
__s += root->i->high;
__s += '"';
__s += "->";
__s += '"';
__s += root->right->i->low;
__s += ',';
__s += root->right->i->high;
__s += '"';
__s += "\n";
__s += __inorder_gen(root->right);
}
} else {
if (root->left) {
__s += '"';
__s += std::to_string(root->i->low);
__s += ',';
__s += std::to_string(root->i->high);
__s += '"';
__s += "->";
__s += '"';
__s += std::to_string(root->left->i->low);
__s += ',';
__s += std::to_string(root->left->i->high);
__s += '"';
__s += "\n";
__s += __inorder_gen(root->left);
}
if (root->right) {
__s += '"';
__s += std::to_string(root->i->low);
__s += ',';
__s += std::to_string(root->i->high);
__s += '"';
__s += "->";
__s += '"';
__s += std::to_string(root->right->i->low);
__s += ',';
__s += std::to_string(root->right->i->high);
__s += '"';
__s += "\n";
__s += __inorder_gen(root->right);
}
}
return __s;
}
};

#endif
27 changes: 27 additions & 0 deletions tests/tree/interval_tree.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#define CATCH_CONFIG_MAIN
#include "../../src/classes/tree/interval_tree.h"
#include "../catch2/catch.hpp"
#include <string>

TEST_CASE("testing insertion") {
interval_tree<int> i;
i.insert({20, 36});
i.insert({3, 41});
i.insert({29, 99});
i.insert({0, 1});
i.insert({10, 15});
std::vector<std::pair<int, int>> els = {
{0, 1}, {3, 41}, {10, 15}, {20, 36}, {29, 99}};
REQUIRE(i.inorder() == els);
}

TEST_CASE("testing overlap") {
interval_tree<int> i;
i.insert({20, 36});
i.insert({3, 41});
i.insert({29, 99});
i.insert({0, 1});
i.insert({10, 15});
REQUIRE(i.overlap({20, 36}, {3, 41}) == true);
REQUIRE(i.overlap({20, 36}, {10, 15}) == false);
}
6 changes: 6 additions & 0 deletions tests/tree/unnamed.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
digraph Tree {
"20,36"->"3,41"
"3,41"->"0,1"
"3,41"->"10,15"
"20,36"->"29,99"
}

0 comments on commit b1048f4

Please sign in to comment.