Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions CPP/algorithms/graph_algorithms/hierholzer_algorithm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Algorithm: Hierholzer’s Algorithm (Eulerian Path / Circuit)
*
* Problem:
* Given a connected graph (directed or undirected), find an Eulerian Path or Circuit.
* - Eulerian Path: visits every edge exactly once.
* - Eulerian Circuit: Eulerian Path that starts and ends on the same vertex.
*
* Eulerian Path Conditions:
* - Undirected: At most 2 vertices have odd degree.
* - Directed: exactly 1 vertex has (out = in + 1), exactly 1 has (in = out + 1),
* all others: indegree == outdegree.
*
* Eulerian Circuit Conditions:
* - Undirected: all vertices have even degree.
* - Directed: indegree == outdegree for every vertex.
*
* Approach (Hierholzer’s Algorithm):
* 1. Pick starting vertex:
* - Circuit → any vertex.
* - Path → vertex with (outdeg > indeg).
* 2. Traverse edges using a stack, removing them as you go.
* 3. If stuck, backtrack → add vertex to final path.
* 4. Reverse final path → Eulerian Path / Circuit.
*
* Complexity:
* - O(E), since each edge is used exactly once.
*/

#include <bits/stdc++.h>
using namespace std;

class Eulerian
{
public:
vector<int> findEulerianPath(int n, vector<vector<int>> &edges)
{
vector<vector<int>> adj(n);
vector<int> indeg(n, 0), outdeg(n, 0);

// Build adjacency list
for (auto &e : edges)
{
int u = e[0], v = e[1];
adj[u].push_back(v);
outdeg[u]++;
indeg[v]++;
}

// Find start node (for path vs circuit)
int start = 0;
for (int i = 0; i < n; i++)
{
if (outdeg[i] - indeg[i] == 1)
start = i; // Eulerian path start
}

vector<int> path, stack = {start};

// Hierholzer’s Algorithm
while (!stack.empty())
{
int u = stack.back();
if (!adj[u].empty())
{
// Go deeper using available edge
int v = adj[u].back();
adj[u].pop_back(); // remove edge u→v
stack.push_back(v);

// 🔎 Visualization step
// cout << "Traverse edge " << u << " -> " << v << endl;
}
else
{
// No more edges → add to path (backtrack)
path.push_back(u);
stack.pop_back();

// 🔎 Visualization step
// cout << "Backtrack: add " << u << " to path" << endl;
}
}

reverse(path.begin(), path.end()); // final path
return path;
}
};

int main()
{
// Example Graph: Eulerian Circuit
int n = 4;
vector<vector<int>> edges = {
{0, 1}, {1, 2}, {2, 0}, {0, 3}, {3, 0}};

Eulerian solver;
vector<int> path = solver.findEulerianPath(n, edges);

cout << "Eulerian Path/Circuit: ";
for (int v : path)
cout << v << " ";
cout << endl;

/*
* Visualization for this graph:
*
* Edges: 0->1, 1->2, 2->0, 0->3, 3->0
*
* Step walk:
* Start at 0
* 0 -> 3
* 3 -> 0
* 0 -> 1
* 1 -> 2
* 2 -> 0
*
* Backtracking order:
* 0 (dead end) → 2 → 1 → 0 → 3 → 0
*
* Final Eulerian Circuit:
* 0 → 3 → 0 → 1 → 2 → 0
*/
}
145 changes: 145 additions & 0 deletions CPP/algorithms/graph_algorithms/prims_algorithm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Prim’s Algorithm — Minimum Spanning Tree (MST)
// Problem
// Given a weighted, undirected graph, find a subset of edges
// that connects all vertices with minimum total weight without cycles.
//
// Approach
// 1. Start from any vertex (usually 0), mark it as part of MST.
// 2. Use a priority queue (min-heap) to pick the smallest edge
// connecting MST to a new vertex.
// 3. Add the chosen vertex to MST and repeat until all vertices included.
//
// Complexity
// Time : O((V + E) log V) — using priority queue
// Space : O(V + E) — adjacency list + key array + heap
//
// Input
// - Number of vertices (V)
// - Number of edges (E)
// - Edge list {u, v, w} (u ↔ v with weight w)
//
// Output
// - Total weight of MST
// - Edges included in MST

#include <iostream>
#include <vector>
#include <queue>
#include <limits>
using namespace std;

int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);

int V, E;
cin >> V >> E;
vector<vector<pair<int, int>>> adj(V);


for (int i = 0; i < E; i++)
{
int u, v, w;
cin >> u >> v >> w;
adj[u].push_back({v, w});
adj[v].push_back({u, w}); // undirected graph
}

const int INF = numeric_limits<int>::max();
vector<int> key(V, INF); // minimum edge weight to MST
vector<int> parent(V, -1); // store MST edges
vector<bool> inMST(V, false); // track vertices included

priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;

int start = 0;
key[start] = 0;
pq.push({0, start});

while (!pq.empty())
{
int w = pq.top().first;
int u = pq.top().second;
pq.pop();
if (inMST[u])
continue;

inMST[u] = true;

for (auto &edge : adj[u])
{
int v = edge.first, weight = edge.second;
if (!inMST[v] && weight < key[v])
{
key[v] = weight;
parent[v] = u;
pq.push({key[v], v});
}
}
}

int totalWeight = 0;
cout << "Edges in MST:\n";
for (int v = 0; v < V; v++)
{
if (parent[v] != -1)
{
cout << parent[v] << " - " << v << " (weight " << key[v] << ")\n";
totalWeight += key[v];
}
}
cout << "Total MST weight: " << totalWeight << "\n";

return 0;
}

/*
Example Input:
5 7
0 1 2
0 3 6
1 2 3
1 3 8
1 4 5
2 4 7
3 4 9

Visualization:
Graph:
(2)
0 ------- 1
\ /|\
(6)\ (3)(5)
\ / \
3 4
(9) (7)

Step-by-step Execution:
Start from 0:
- Include 0 → candidate edges: 0→1(2), 0→3(6)
- Pick min edge 0→1(2) → add 1
- Candidate edges: 1→2(3), 1→3(8), 1→4(5), 0→3(6)
- Pick min edge 1→2(3) → add 2
- Candidate edges: 1→3(8), 1→4(5), 2→4(7), 0→3(6)
- Pick min edge 1→4(5) → add 4
- Candidate edges: 0→3(6), 1→3(8), 2→4(7), 3→4(9)
- Pick min edge 0→3(6) → add 3
All vertices included → MST complete

MST edges:
0 - 1 (2)
1 - 2 (3)
1 - 4 (5)
0 - 3 (6)
Total MST weight: 16

Time : O((V+E) log V)
Space : O(V+E)
*/

// add: Prim PR

// prepare Prim PR

// prepare PR