diff --git a/examples/tree/avl.cc b/examples/tree/avl.cc index ac7743f3..d97c6c0e 100644 --- a/examples/tree/avl.cc +++ b/examples/tree/avl.cc @@ -5,6 +5,18 @@ int main() { avl_tree a; + avl_tree> b; + b.insert({4, 5, 6}); + b.insert({1, 3, 4}); + b.insert({5, 6, 7}); + std::vector> 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); diff --git a/src/classes/graph/graph.h b/src/classes/graph/graph.h index a36198a6..4cd316cb 100644 --- a/src/classes/graph/graph.h +++ b/src/classes/graph/graph.h @@ -51,6 +51,10 @@ template class graph { int64_t connected_components(); + bool cycle(); + + std::vector topological_sort(); + private: std::unordered_map> adj; std::unordered_set __elements; @@ -102,15 +106,15 @@ template std::vector graph::bfs(T start) { template int64_t graph::connected_components() { auto explore = [&](std::unordered_map &visited, T element) -> void { - std::stack s; - s.push(element); + std::queue 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; } } @@ -128,6 +132,71 @@ template int64_t graph::connected_components() { return cc; } +template bool graph::cycle() { + std::unordered_map indeg; + std::queue 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 std::vector graph::topological_sort() { + std::vector top_sort; + std::unordered_map visited; + std::unordered_map indeg; + for (T x : __elements) { + for (T &y : adj[x]) { + indeg[y]++; + } + } + + std::queue 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 class weighted_graph { public: weighted_graph(std::string __type, @@ -171,6 +240,10 @@ template class weighted_graph { int64_t connected_components(); + bool cycle(); + + std::vector topological_sort(); + private: std::unordered_map>> adj; std::string __type; @@ -186,27 +259,54 @@ template int64_t weighted_graph::shortest_path(T start, T end) { std::cout << "Element: " << end << " is not found in the Graph" << '\n'; return -1; } - std::unordered_map dist; - for (auto &x : __elements) { - dist[x] = INT_MAX; - } - std::priority_queue, std::vector>, - std::greater>> - 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 &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 top_sort = topological_sort(); + std::reverse(top_sort.begin(), top_sort.end()); + std::stack s; + std::unordered_map 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 &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 dist; + for (auto &x : __elements) { + dist[x] = INT_MAX; + } + std::priority_queue, + std::vector>, + std::greater>> + 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 &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 std::vector weighted_graph::dfs(T start) { @@ -282,4 +382,69 @@ template int64_t weighted_graph::connected_components() { } return cc; } + +template bool weighted_graph::cycle() { + std::unordered_map indeg; + std::queue q; + size_t visited = 0; + + for (T x : __elements) { + for (std::pair &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 &x : adj[current]) { + if (--indeg[x.first] == 0) { + q.push(x.first); + } + } + } + return visited == 0; +} + +template std::vector weighted_graph::topological_sort() { + std::vector top_sort; + std::unordered_map visited; + std::unordered_map indeg; + for (T x : __elements) { + for (std::pair &y : adj[x]) { + indeg[y.first]++; + } + } + + std::queue 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 &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 \ No newline at end of file diff --git a/tests/graph/graph.cc b/tests/graph/graph.cc index e2f1b1ae..e8068cf7 100644 --- a/tests/graph/graph.cc +++ b/tests/graph/graph.cc @@ -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 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 g("undirected"); + g.add_edge(1, 2); + g.add_edge(2, 3); + g.add_edge(3, 1); + REQUIRE(g.cycle() == true); + + graph g2("directed"); + g2.add_edge(1, 2); + g2.add_edge(2, 3); + g2.add_edge(3, 1); + REQUIRE(g2.cycle() == true); + + graph 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 g("directed"); + g.add_edge(0, 1); + g.add_edge(1, 3); + g.add_edge(2, 3); + g.add_edge(3, 4); + std::vector v1 = {2, 0, 1, 3, 4}; + REQUIRE(g.topological_sort() == v1); } diff --git a/tests/graph/weighted_graph.cc b/tests/graph/weighted_graph.cc index 180bce04..961bfee8 100644 --- a/tests/graph/weighted_graph.cc +++ b/tests/graph/weighted_graph.cc @@ -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 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 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 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 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); } \ No newline at end of file