16#include <unordered_map>
17#include <unordered_set>
37template <
class T,
class W>
39 size_t operator()(
const std::pair<T, W>& lhs)
const {
return std::hash<T>{}(lhs.first); }
42template <
class T,
class W>
44 bool operator()(
const std::pair<T, W>& lhs,
const std::pair<T, W>& rhs)
const {
45 return std::equal_to<T>{}(lhs.first, rhs.first);
65template <
class T, std::default_initializable W,
class EdgeHash = EdgeHash_<T, W>,
class EdgeEqual = EdgeEqual_<T, W>>
68 using Edge = std::pair<T, W>;
69 using AdjSet = std::unordered_set<Edge, EdgeHash, EdgeEqual>;
104 void AddEdge(
const T& u,
const T& v,
bool bidirectional =
true) {
107 if (bidirectional)
adj_list_[v].emplace(u, 1);
121 bool AddEdge(
const T& u,
const T& v,
const W& weight,
bool bidirectional =
true) {
122 bool updated =
false;
123 const auto [it, inserted] =
adj_list_[u].emplace(v, weight);
125 if (!inserted && it->second != weight) {
131 const auto [b_it, b_inserted] =
adj_list_[v].emplace(u, 1 / weight);
132 if (!b_inserted && b_it->second != 1 / weight) {
197 void RemoveEdge(
const T& u,
const T& v,
bool bidirectional =
true) {
199 if (bidirectional)
adj_list_[v].erase({u, W{}});
208 for (
auto& [node, edges] :
adj_list_) edges.erase({v, W{}});
215 for (
auto& [node, edges] : adj_list_) edges.clear();
222 [[nodiscard]]
size_t Size()
const {
223 return std::accumulate(adj_list_.begin(), adj_list_.end(), 0,
224 [](
size_t acc,
const auto& pair) { return acc + pair.second.size(); });
232 [[nodiscard]]
bool IsEmpty()
const {
return adj_list_.empty(); }
248 std::unordered_set<T> visited{};
249 DFS(start, func, visited);
268 void DFS(
const T& start,
const VisitFunc& func, std::unordered_set<T>& visited) {
270 if (adj_list_.find(start) == adj_list_.end())
return;
272 visited.reserve(adj_list_.size());
274 std::unordered_map<T, std::pair<T, const W*>> edges;
276 edges.emplace(start, std::make_pair(start, &zero_));
278 while (!stack.empty()) {
279 const T current = std::move(stack.top());
281 if (visited.find(current) != visited.end())
continue;
282 visited.insert(current);
283 const VisitResult res = func(edges.at(current).first, current, *edges.at(current).second);
284 if (res == VisitResult::STOP)
return;
285 if (res == VisitResult::SKIP || adj_list_.find(current) == adj_list_.end())
continue;
286 for (
auto adj_it = adj_list_.at(current).begin(); adj_it != adj_list_.at(current).end(); ++adj_it) {
287 const auto& [adj_vertex, weight] = *adj_it;
288 if (visited.find(adj_vertex) != visited.end())
continue;
289 stack.push(adj_vertex);
290 edges.insert_or_assign(adj_vertex, std::make_pair(current, &weight));
309 std::unordered_set<T> visited{};
310 BFS(start, func, visited);
328 void BFS(
const T& start,
const VisitFunc& func, std::unordered_set<T>& visited) {
330 if (adj_list_.find(start) == adj_list_.end())
return;
332 visited.reserve(adj_list_.size());
334 std::unordered_map<T, std::pair<T, const W*>> edges;
336 visited.insert(start);
337 edges.emplace(start, std::make_pair(start, &zero_));
339 while (!queue.empty()) {
340 const VisitResult res = func(edges.at(queue.front()).first, queue.front(), *edges.at(queue.front()).second);
341 if (res == VisitResult::STOP)
return;
342 if (res == VisitResult::SKIP || adj_list_.find(queue.front()) == adj_list_.end()) {
346 for (
auto adj_it = adj_list_.at(queue.front()).begin(); adj_it != adj_list_.at(queue.front()).end(); ++adj_it) {
347 const auto& [adj_vertex, weight] = *adj_it;
348 if (visited.find(adj_vertex) != visited.end())
continue;
349 visited.insert(adj_vertex);
350 queue.push(adj_vertex);
351 edges.insert_or_assign(adj_vertex, std::make_pair(queue.front(), &weight));
374 std::unordered_set<T> visited;
375 AllPaths(start, end, func, visited);
396 void AllPaths(
const T& start,
const T& end,
const PathsFunc& func, std::unordered_set<T>& visited) {
397 if (adj_list_.find(start) == adj_list_.end() || adj_list_.find(end) == adj_list_.end() ||
398 adj_list_.find(start) == adj_list_.find(end))
401 std::unordered_map<T, typename std::unordered_set<Edge>::iterator> iterators;
404 iterators.reserve(adj_list_.size());
405 visited.reserve(adj_list_.size());
406 path.reserve(adj_list_.size());
409 visited.insert(start);
410 path.push_back(start);
411 iterators[start] = adj_list_[start].begin();
413 while (!stack.empty()) {
414 const T current = stack.top();
416 if (current == end) {
417 if (func(path) != VisitResult::CONTINUE)
return;
419 visited.erase(current);
424 auto& it = iterators.at(current);
425 if (it == adj_list_.at(current).end()) {
427 visited.erase(current);
432 const T next = it->first;
434 if (visited.find(next) == visited.end()) {
436 visited.insert(next);
437 path.push_back(next);
438 iterators.insert_or_assign(next, adj_list_.at(next).begin());
448template <
class T,
class E>
449std::ostream& operator<<(std::ostream& os,
const Graph<T, E>& s) {
451 for (
const auto& [vertex, edges] : s.
adj_list()) {
452 os <<
"| " << vertex <<
" | -> ";
453 for (
const auto& [adj_vertex, weight] : edges) os << adj_vertex <<
"(" << weight <<
"), ";
std::unordered_map< T, AdjSet > adj_list_
Adjacency list of the graph.
void AllPaths(const T &start, const T &end, const PathsFunc &func)
Find all paths from vertex start to vertex end.
const W * GetEdgeWeight(const T &u, const T &v) const
Get a pointer to the weight of the edge from vertex u to vertex v.
void Clear()
Clear the graph, removing all vertices and edges.
void ClearEdges()
Clear the graph, removing only the edges and leaving the vertices.
void AddVertex(const T &v)
Add a vertex v to the graph.
bool HasEdges(const T &u) const
Check if there are any positive number of vertexes starting from vertex u.
void AddEdge(const T &u, const T &v, bool bidirectional=true)
Add an edge to the graph from vertex u to vertex v.
bool AddEdge(const T &u, const T &v, const W &weight, bool bidirectional=true)
Add an edge to the graph from vertex u to vertex v.
size_t Size() const
Return the number of vertices in the graph.
void BFS(const T &start, const VisitFunc &func, std::unordered_set< T > &visited)
Explore the graph using breadth-first search starting from vertex start.
std::function< VisitResult(const T &, const T &, const W &)> VisitFunc
Visit function for DFS and BFS.
void DFS(const T &start, const VisitFunc &func, std::unordered_set< T > &visited)
Explore the graph using depth-first search starting from vertex start.
std::function< VisitResult( std::vector< T > &)> PathsFunc
Function to call on each path found.
void AllPaths(const T &start, const T &end, const PathsFunc &func, std::unordered_set< T > &visited)
Find all paths from vertex start to vertex end.
void RemoveVertex(const T &v)
Remove a vertex v from the graph.
void RemoveEdge(const T &u, const T &v, bool bidirectional=true)
Remove an edge from vertex u to vertex v.
bool HasEdge(const T &u, const T &v) const
Check if the graph contains an edge from vertex u to vertex v.
void BFS(const T &start, const VisitFunc &func)
Explore the graph using breadth-first search starting from vertex start.
const std::unordered_map< T, AdjSet > & adj_list() const
Return the adjacency list of the graph.
bool IsEmpty() const
Check if the graph is empty.
void DFS(const T &start, const VisitFunc &func)
Explore the graph using depth-first search starting from vertex start.
Global namespace for the dlinear library.
VisitResult
Result returned by the visit function.
@ CONTINUE
Continue the search as usual and add the adjacent vertices to the stack/queue.
@ STOP
Stop the search altogether.
@ SKIP
Skip adding the adjacent vertices to the stack/queue, but continue the search.