Skip to content

Commit

Permalink
updated graph class and test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
spirosmaggioros committed Jan 13, 2024
1 parent 7c83a8f commit 3136ad5
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 24 deletions.
12 changes: 12 additions & 0 deletions examples/tree/avl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@

int main() {
avl_tree<int> a;
avl_tree<std::vector<int>> b;
b.insert({4, 5, 6});
b.insert({1, 3, 4});
b.insert({5, 6, 7});
std::vector<std::vector<int>> r = b.inorder();
for (auto &x : r) {
for (auto &y : x) {
std::cout << y << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
a.insert(1);
a.insert(-10);
a.insert(10);
Expand Down
213 changes: 189 additions & 24 deletions src/classes/graph/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ template <typename T> class graph {

int64_t connected_components();

bool cycle();

std::vector<T> topological_sort();

private:
std::unordered_map<T, std::vector<T>> adj;
std::unordered_set<T> __elements;
Expand Down Expand Up @@ -102,15 +106,15 @@ template <typename T> std::vector<T> graph<T>::bfs(T start) {

template <typename T> int64_t graph<T>::connected_components() {
auto explore = [&](std::unordered_map<T, bool> &visited, T element) -> void {
std::stack<T> s;
s.push(element);
std::queue<T> q;
q.push(element);
visited[element] = true;
while (!s.empty()) {
T current = s.top();
s.pop();
while (!q.empty()) {
T current = q.front();
q.pop();
for (T &x : adj[current]) {
if (visited.find(x) == visited.end()) {
s.push(x);
q.push(x);
visited[x] = true;
}
}
Expand All @@ -128,6 +132,71 @@ template <typename T> int64_t graph<T>::connected_components() {
return cc;
}

template <typename T> bool graph<T>::cycle() {
std::unordered_map<T, int> indeg;
std::queue<T> q;
size_t visited = 0;

for (T x : __elements) {
for (T &y : adj[x]) {
indeg[y]++;
}
}

for (T x : __elements) {
if (indeg[x] == 0) {
q.push(x);
}
}

while (!q.empty()) {
T current = q.front();
q.pop();
visited++;
for (T &x : adj[current]) {
if (--indeg[x] == 0) {
q.push(x);
}
}
}
return visited == 0;
}

template <typename T> std::vector<T> graph<T>::topological_sort() {
std::vector<T> top_sort;
std::unordered_map<T, bool> visited;
std::unordered_map<T, int64_t> indeg;
for (T x : __elements) {
for (T &y : adj[x]) {
indeg[y]++;
}
}

std::queue<T> q;
for (T x : __elements) {
if (indeg[x] == 0) {
q.push(x);
visited[x] = true;
}
}

while (!q.empty()) {
T current = q.front();
q.pop();
top_sort.push_back(current);
for (T &x : adj[current]) {
if (visited.find(x) == visited.end()) {
if (--indeg[x] == 0) {
q.push(x);
visited[x] = true;
}
}
}
}

return top_sort;
}

template <typename T> class weighted_graph {
public:
weighted_graph(std::string __type,
Expand Down Expand Up @@ -171,6 +240,10 @@ template <typename T> class weighted_graph {

int64_t connected_components();

bool cycle();

std::vector<T> topological_sort();

private:
std::unordered_map<T, std::vector<std::pair<T, int64_t>>> adj;
std::string __type;
Expand All @@ -186,27 +259,54 @@ template <typename T> int64_t weighted_graph<T>::shortest_path(T start, T end) {
std::cout << "Element: " << end << " is not found in the Graph" << '\n';
return -1;
}
std::unordered_map<T, int64_t> dist;
for (auto &x : __elements) {
dist[x] = INT_MAX;
}
std::priority_queue<std::pair<int64_t, T>, std::vector<std::pair<int64_t, T>>,
std::greater<std::pair<int64_t, T>>>
pq;
pq.push(std::make_pair(0, start));
dist[start] = 0;
while (!pq.empty()) {
T currentNode = pq.top().second;
T currentDist = pq.top().first;
pq.pop();
for (std::pair<T, int64_t> &edge : adj[currentNode]) {
if (currentDist + edge.second < dist[edge.first]) {
dist[edge.first] = currentDist + edge.second;
pq.push(std::make_pair(dist[edge.first], edge.first));

if (!cycle()) {
std::vector<T> top_sort = topological_sort();
std::reverse(top_sort.begin(), top_sort.end());
std::stack<T> s;
std::unordered_map<T, int64_t> dist;
for (auto &x : __elements) {
dist[x] = INT_MAX;
}
dist[start] = 0;
while (!top_sort.empty()) {
auto current = top_sort.back();
top_sort.pop_back();
if (dist[current] != INT_MAX) {
for (std::pair<T, int64_t> &x : adj[current]) {
if (dist[x.first] > dist[current] + x.second) {
dist[x.first] = dist[current] + x.second;
top_sort.push_back(x.first);
}
}
}
}
return (dist[end] != INT_MAX) ? dist[end] : -1;
} else {
std::unordered_map<T, int64_t> dist;
for (auto &x : __elements) {
dist[x] = INT_MAX;
}
std::priority_queue<std::pair<int64_t, T>,
std::vector<std::pair<int64_t, T>>,
std::greater<std::pair<int64_t, T>>>
pq;
pq.push(std::make_pair(0, start));
dist[start] = 0;
while (!pq.empty()) {
T currentNode = pq.top().second;
T currentDist = pq.top().first;
pq.pop();
for (std::pair<T, int64_t> &edge : adj[currentNode]) {
if (currentDist + edge.second < dist[edge.first]) {
dist[edge.first] = currentDist + edge.second;
pq.push(std::make_pair(dist[edge.first], edge.first));
}
}
}
return (dist[end] != INT_MAX) ? dist[end] : -1;
}
return (dist[end] != INT_MAX) ? dist[end] : -1;
return -1;
}

template <typename T> std::vector<T> weighted_graph<T>::dfs(T start) {
Expand Down Expand Up @@ -282,4 +382,69 @@ template <typename T> int64_t weighted_graph<T>::connected_components() {
}
return cc;
}

template <typename T> bool weighted_graph<T>::cycle() {
std::unordered_map<T, int> indeg;
std::queue<T> q;
size_t visited = 0;

for (T x : __elements) {
for (std::pair<T, int64_t> &y : adj[x]) {
indeg[y.first]++;
}
}

for (T x : __elements) {
if (indeg[x] == 0) {
q.push(x);
}
}

while (!q.empty()) {
T current = q.front();
q.pop();
visited++;
for (std::pair<T, int64_t> &x : adj[current]) {
if (--indeg[x.first] == 0) {
q.push(x.first);
}
}
}
return visited == 0;
}

template <typename T> std::vector<T> weighted_graph<T>::topological_sort() {
std::vector<T> top_sort;
std::unordered_map<T, bool> visited;
std::unordered_map<T, int64_t> indeg;
for (T x : __elements) {
for (std::pair<T, int64_t> &y : adj[x]) {
indeg[y.first]++;
}
}

std::queue<T> q;
for (T x : __elements) {
if (indeg[x] == 0) {
q.push(x);
visited[x] = true;
}
}

while (!q.empty()) {
T current = q.front();
q.pop();
top_sort.push_back(current);
for (std::pair<T, int64_t> &x : adj[current]) {
if (visited.find(x.first) == visited.end()) {
if (--indeg[x.first] == 0) {
q.push(x.first);
visited[x.first] = true;
}
}
}
}

return top_sort;
}
#endif
37 changes: 37 additions & 0 deletions tests/graph/graph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,41 @@ TEST_CASE("testing connecting components") {
g.add_edge(5, 6);
g.add_edge(7, 8);
REQUIRE(g.connected_components() == 3);

graph<char> g2("undirected");
g2.add_edge('a', 'g');
g2.add_edge('b', 'o');
g2.add_edge('o', 'a');
g2.add_edge('w', 'e');
REQUIRE(g2.connected_components() == 2);
}

TEST_CASE("testing cycle detection") {
graph<int> g("undirected");
g.add_edge(1, 2);
g.add_edge(2, 3);
g.add_edge(3, 1);
REQUIRE(g.cycle() == true);

graph<int> g2("directed");
g2.add_edge(1, 2);
g2.add_edge(2, 3);
g2.add_edge(3, 1);
REQUIRE(g2.cycle() == true);

graph<int> g3("directed");
g3.add_edge(4, 5);
g3.add_edge(5, 6);
g3.add_edge(4, 6);
REQUIRE(g3.cycle() == false);
}

TEST_CASE("testing topological sorting") {
graph<int> g("directed");
g.add_edge(0, 1);
g.add_edge(1, 3);
g.add_edge(2, 3);
g.add_edge(3, 4);
std::vector<int> v1 = {2, 0, 1, 3, 4};
REQUIRE(g.topological_sort() == v1);
}
33 changes: 33 additions & 0 deletions tests/graph/weighted_graph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,37 @@ TEST_CASE("testing conected components") {
g2.add_edge(2, 3, 5);
g2.add_edge(3, 5, 7);
REQUIRE(g2.connected_components() == 1);
}

TEST_CASE("testing cycle detection") {
weighted_graph<int> g("undirected");
g.add_edge(0, 1, 0);
g.add_edge(2, 3, 4);
g.add_edge(1, 2, 10);
g.add_edge(3, 0, 9);
REQUIRE(g.cycle() == true);

weighted_graph<int> g2("directed");
g2.add_edge(0, 1, 0);
g2.add_edge(2, 3, 0);
g2.add_edge(1, 2, 0);
g2.add_edge(0, 3, 0);
REQUIRE(g2.cycle() == false);
}

TEST_CASE("testing shortest path in DAG") {
weighted_graph<int> g2("directed");
g2.add_edge(0, 1, 10);
g2.add_edge(2, 3, 8);
g2.add_edge(1, 2, 6);
g2.add_edge(0, 3, 4);
REQUIRE(g2.shortest_path(0, 3) == 4);

weighted_graph<int> g3("directed");
g3.add_edge(0, 1, 0);
g3.add_edge(1, 2, 2);
g3.add_edge(2, 6, 3);
g3.add_edge(1, 6, 1);
g3.add_edge(3, 2, 4);
REQUIRE(g3.shortest_path(0, 6) == 1);
}

0 comments on commit 3136ad5

Please sign in to comment.