A modern C++ library for graph data structures and algorithms with template-based flexibility and type safety.
- Multiple Graph Types: Support for both undirected (
Graph) and directed graphs (DiGraph) - Generic Data Types: Flexible node and edge data storage with template parameters
- Graph Operations: Add/remove nodes and edges with efficient adjacency list implementation
- Comprehensive Algorithms:
- Traversal: BFS, DFS
- Shortest Paths: 8 algorithms (Dijkstra, Bellman-Ford, A*, Floyd-Warshall, Johnson, Bidirectional Dijkstra, Yen K-Shortest Paths, Suurballe)
- Components: Connected Components, Strongly Connected Components
- Ordering: Topological Sort
- Maximum Flow: Dinic's Algorithm, Edmonds-Karp Algorithm
- Graph Construction: Factory Pattern, Fluent Builder Interface
- Graph I/O: Edge List, GraphML, DIMACS formats
- Type Safety: Compile-time type checking for node IDs, node data, and edge data
- C++17 Compatible: Modern C++ features with full type safety
- Header-only: No external dependencies
No dependencies! This project is header-only.
cd graphx
mkdir -p build && cd build
cmake ..
make# Basic API Operations
./demo_api_basics
# Graph Traversal Algorithms (BFS, DFS, Components, SCC)
./demo_traversals
# 8 Shortest Path Algorithms
./demo_shortest_paths
# Graph I/O Operations (Edge List, GraphML, DIMACS)
./demo_io
# Factory Pattern and Builder Interface
./demo_factory
# Maximum Flow Algorithms (Edmonds-Karp, Dinic)
./demo_maxflowSee DEMO.md for detailed demo information.
#include "GraphX/Graph.hpp"
using namespace GraphX;
Graph<int, std::string, double> g;
// Add nodes
g.add_node(1, "Beijing");
g.add_node(2, "Shanghai");
// Add edges
g.add_edge(1, 2, 1064.7); // Distance in km
// Query graph properties
std::cout << "Nodes: " << g.node_count() << "\n";
std::cout << "Node 1: " << g[1] << "\n";
// Get neighbors
for (auto neighbor : g.neighbors(1)) {
std::cout << "Neighbor: " << neighbor << "\n";
}#include "GraphX/GraphAlgorithms.hpp"
// BFS traversal
algorithms::bfs(g, 1, [](int node) {
std::cout << "Visiting: " << node << "\n";
});
// Dijkstra's shortest path
auto distances = algorithms::shortest_paths::Dijkstra<decltype(g)>::compute(g, 1);
// Connected components
auto components = algorithms::connected_components(g);
// Topological sort for DAG
auto topo_order = algorithms::topological_sort(dag);#include "GraphX/GraphFactory.hpp"
// Using Factory
auto graph = GraphFactory::create_graph<int, std::string, double>();
// Using Builder (Fluent Interface)
auto network = GraphBuilder<Graph<int, std::string, double>>()
.add_node(1, "A")
.add_node(2, "B")
.add_node(3, "C")
.add_edge(1, 2, 10.0)
.add_edge(2, 3, 20.0)
.build();
// Creating from edge list
std::vector<std::tuple<int, int, double>> edges = {
{1, 2, 10.0},
{2, 3, 20.0}
};
auto g = GraphFactory::from_edge_list(edges);#include "GraphX/algorithms/maxflow_dinic.hpp"
#include "GraphX/algorithms/maxflow_edmonds_karp.hpp"
// Using Dinic's Algorithm (faster)
auto result = algorithms::maxflow::Dinic<DiGraph>::compute(g, source, sink);
std::cout << "Max Flow: " << result.max_flow << "\n";
// Using Edmonds-Karp Algorithm
auto ek_result = algorithms::maxflow::EdmondsKarp<DiGraph>::compute(g, source, sink);#include "GraphX/GraphIO.hpp"
// Write edge list
io::EdgeListIO<Graph>::write("graph.txt", g);
// Write GraphML
io::GraphMLIO<Graph>::write("graph.graphml", g);
// Write DIMACS
io::DIMACS_IO<Graph>::write("graph.dimacs", g, 1, 4);
// Read edge list
auto g2 = io::EdgeListIO<Graph>::read("graph.txt");graphx/
├── include/GraphX/
│ ├── Graph.hpp
│ ├── DiGraph.hpp
│ ├── GraphFactory.hpp
│ ├── GraphAlgorithms.hpp
│ ├── GraphIO.hpp
│ ├── algorithms/
│ │ ├── bfs.hpp
│ │ ├── dfs.hpp
│ │ ├── connected_components.hpp
│ │ ├── strongly_connected_components.hpp
│ │ ├── topological_sort.hpp
│ │ ├── detail/
│ │ │ └── shortest_path_common.hpp
│ │ ├── shortest_paths/
│ │ │ ├── dijkstra.hpp
│ │ │ ├── bellman_ford.hpp
│ │ │ ├── astar.hpp
│ │ │ ├── bidirectional_dijkstra.hpp
│ │ │ ├── floyd_warshall.hpp
│ │ │ ├── johnson.hpp
│ │ │ ├── yen_ksp.hpp
│ │ │ └── suurballe.hpp
│ │ ├── shortest_paths.hpp
│ │ ├── maxflow_dinic.hpp
│ │ └── maxflow_edmonds_karp.hpp
│ └── io/
│ ├── edge_list.hpp
│ ├── graphml.hpp
│ └── dimacs.hpp
├── src/
│ ├── demo_api_basics.cpp
│ ├── demo_traversals.cpp
│ ├── demo_shortest_paths.cpp
│ ├── demo_io.cpp
│ ├── demo_factory.cpp
│ ├── demo_maxflow.cpp
│ └── demo_extended.cpp
├── doc/
│ ├── algorithms/
│ │ ├── bfs.md
│ │ ├── bfs_zh.md
│ │ ├── dfs.md
│ │ ├── dfs_zh.md
│ │ ├── connected_components.md
│ │ ├── connected_components_zh.md
│ │ ├── strongly_connected_components.md
│ │ ├── strongly_connected_components_zh.md
│ │ ├── topological_sort.md
│ │ ├── topological_sort_zh.md
│ │ ├── shortest_paths.md
│ │ ├── shortest_paths_zh.md
│ │ ├── dijkstra.md
│ │ ├── dijkstra_zh.md
│ │ ├── bellman_ford.md
│ │ ├── bellman_ford_zh.md
│ │ ├── astar.md
│ │ ├── astar_zh.md
│ │ ├── bidirectional_dijkstra.md
│ │ ├── bidirectional_dijkstra_zh.md
│ │ ├── floyd_warshall.md
│ │ ├── floyd_warshall_zh.md
│ │ ├── johnson.md
│ │ ├── johnson_zh.md
│ │ ├── yen_ksp.md
│ │ ├── yen_ksp_zh.md
│ │ ├── suurballe.md
│ │ ├── suurballe_zh.md
│ │ ├── maxflow_edmonds_karp.md
│ │ ├── maxflow_edmonds_karp_zh.md
│ │ ├── maxflow_dinic.md
│ │ ├── maxflow_dinic_zh.md
│ │ ├── detail_shortest_path_common.md
│ │ └── detail_shortest_path_common_zh.md
│ └── README.md
├── CMakeLists.txt
├── README.md
├── DEMO_README.md
└── C++14_COMPATIBILITY.md| Algorithm | File | Time | Space | Use Case |
|---|---|---|---|---|
| BFS | bfs.hpp |
O(V+E) | O(V) | Shortest path in unweighted graphs, layer-by-layer traversal |
| DFS | dfs.hpp |
O(V+E) | O(V) | Topological sort, cycle detection, SCC preparation |
| Algorithm | File | Time | Space | Use Case |
|---|---|---|---|---|
| Connected Components | connected_components.hpp |
O(V+E) | O(V) | Find all components in undirected graph |
| Strongly Connected Components | strongly_connected_components.hpp |
O(V+E) | O(V) | Find SCCs in directed graph using Tarjan |
| Topological Sort | topological_sort.hpp |
O(V+E) | O(V) | DAG ordering using Kahn or DFS |
| Algorithm | File | Time | Space | Best For |
|---|---|---|---|---|
| Dijkstra | shortest_paths/dijkstra.hpp |
O((V+E)logV) | O(V) | Non-negative weights, single-source |
| Bellman-Ford | shortest_paths/bellman_ford.hpp |
O(VE) | O(V) | Negative weights, negative cycle detection |
| A* | shortest_paths/astar.hpp |
Variable | O(V) | Pathfinding with heuristic |
| Bidirectional Dijkstra | shortest_paths/bidirectional_dijkstra.hpp |
O((V+E)logV) | O(V) | Point-to-point queries, often faster |
| Floyd-Warshall | shortest_paths/floyd_warshall.hpp |
O(V³) | O(V²) | All-pairs, small/dense graphs |
| Johnson | shortest_paths/johnson.hpp |
O(VE + V²logV) | O(V²) | All-pairs, sparse graphs |
| Yen's K-Shortest Paths | shortest_paths/yen_ksp.hpp |
O(K·V·E·logV) | O(V+E) | Find K loopless shortest paths |
| Suurballe | shortest_paths/suurballe.hpp |
O((V+E)logV) | O(V+E) | Two edge-disjoint shortest paths |
| Algorithm | File | Time | Space | Best For |
|---|---|---|---|---|
| Edmonds-Karp | maxflow_edmonds_karp.hpp |
O(VE²) | O(V+E) | Simple, reliable, educational |
| Dinic | maxflow_dinic.hpp |
O(V²E) | O(V+E) | Large networks, practical efficiency |
Graph<int, std::string, double> g;
// Add nodes
g.add_node(1, "Node A");
g.add_node(2, "Node B");
// Query nodes
g.has_node(1); // bool
g.node_count(); // size_t
g.nodes(); // vector<NodeId>
// Access/modify node data
auto data = g[1];
g[1] = "Updated Label";
// Add/remove edges
g.add_edge(1, 2, 5.0);
g.remove_edge(1, 2);
// Query edges
g.has_edge(1, 2);
g.edge(1, 2); // Get edge weight
g.degree(1); // Node degree
g.neighbors(1); // Adjacent nodes
g.edges(); // All edges as vector<tuple<u,v,w>>DiGraph<int, std::string, double> dg;
dg.add_node(1, "A");
dg.add_edge(1, 2, 1.0);
// Directed-specific queries
dg.in_degree(2); // Number of incoming edges
dg.out_degree(1); // Number of outgoing edges
dg.predecessors(2); // Nodes pointing to 2
dg.successors(1); // Nodes pointed to by 1
dg.is_directed(); // bool (true for DiGraph)// Factory method
auto g1 = GraphFactory::create_graph<int, std::string, double>();
// Builder with fluent interface
auto g2 = GraphBuilder<Graph<int, std::string, double>>()
.add_node(1, "A")
.add_node(2, "B")
.add_edge(1, 2, 10.0)
.build();
// From edge list
std::vector<std::tuple<int, int, double>> edges = {{1,2,10}, {2,3,20}};
auto g3 = GraphFactory::from_edge_list(edges);
// From directed edge list
auto g4 = GraphFactory::from_directed_edge_list(edges);Comprehensive algorithm documentation is available in the doc/ directory with both English and Chinese versions:
- Traversal: BFS, DFS
- Components: Connected Components, Strongly Connected Components
- Shortest Paths: All 8 algorithms with complexity analysis and use cases
- Maximum Flow: Edmonds-Karp and Dinic with real-world examples
- Utilities: Common helpers and implementation notes
Each algorithm document includes:
- Algorithm overview and key concepts
- Time and space complexity analysis
- Public API documentation
- Implementation notes specific to this project
- Example usage patterns
- References
Access with doc/algorithm_name.md (English) or doc/algorithm_name_zh.md (Chinese).
- C++17 or later (main branch)
- C++14 compatible version available with configuration
- CMake 3.10+
- Standard C++ library (no external dependencies)
The project includes six comprehensive demo programs showcasing different features:
- demo_api_basics - Graph construction, node/edge operations, queries
- demo_traversals - BFS, DFS, connected components, strongly connected components
- demo_shortest_paths - All 8 shortest path algorithms with comparisons
- demo_io - Reading/writing graphs in multiple formats
- demo_factory - Factory patterns and builder interface for graph construction
- demo_maxflow - Maximum flow algorithms with real-world applications
Run all demos:
cd build
./demo_api_basics && ./demo_traversals && ./demo_shortest_paths && \
./demo_io && ./demo_factory && ./demo_maxflowGraphX uses a flexible template-based type system:
// NodeId: type of node identifiers (int, string, etc.)
// NodeData: data stored at each node (string, struct, etc.)
// EdgeData: data stored at each edge/weight (double, struct, etc.)
Graph<NodeId, NodeData, EdgeData> g;
// Example: City network with populations and distances
Graph<int, std::string, double> cities;
// Example: Program dependency graph with names and artifact sizes
Graph<std::string, std::pair<std::string, int>, double> build_graph;| Operation | Time | Notes |
|---|---|---|
| Add node | O(1) | Hash table insertion |
| Remove node | O(V + E) | Must remove from all adjacency lists |
| Add edge | O(1) | Hash table insertion |
| Remove edge | O(degree) | Linear search in edge vector |
| Query has_edge | O(degree) | Linear search in edge vector |
| Get neighbors | O(degree) | Returns vector of neighbors |
| Get node count | O(1) | Cached |
| Get edge count | O(1) | Cached |
| Get degree | O(1) | Cached in node info |
| Get all nodes | O(V) | Returns copy of node list |
| Get all edges | O(V + E) | Iterates all adjacency lists |
Contributions are welcome! Please:
- Follow the existing code style
- Add tests for new features
- Update documentation (English and Chinese)
- Include example code in demos
- Submit pull requests with clear descriptions
MIT License
- Cormen, Leiserson, Rivest, Stein - Introduction to Algorithms (CLRS)
- Tarjan - Depth-First Search and Linear Graph Algorithms (1972)
- Dijkstra - A Note on Two Problems in Connexion with Graphs (1959)
- Bellman - On a Routing Problem (1958)
- Floyd - Algorithm 97: Shortest Path (1962)
- Yen - Finding the K Shortest Loopless Paths in a Network (1971)
- Suurballe - Disjoint Paths in a Network (1974)
- Edmonds & Karp - Theoretical Improvements in Algorithmic Efficiency (1972)
- Dinic - Algorithm for Solution of a Problem of Maximum Flow in Networks (1970)
This library is designed for educational and practical applications, combining modern C++ practices with classical graph algorithms.