andres::graph
dfs.hxx
1 #pragma once
2 #ifndef ANDRES_GRAPH_DFS_HXX
3 #define ANDRES_GRAPH_DFS_HXX
4 
5 #include <cassert>
6 #include <cstddef>
7 #include <stack>
8 #include <type_traits>
9 #include <vector>
10 
11 #include "subgraph.hxx"
12 
13 namespace andres {
14 namespace graph {
15 
16 template<typename S = std::size_t>
18 public:
19  typedef S size_type;
20 
22  : visited_(size)
23  {}
24  template<typename GRAPH>
25  DepthFirstSearchData(const GRAPH& graph)
26  : visited_(graph.numberOfVertices())
27  {}
29  { stack_.push(v); }
30  void clearStack()
31  { stack_ = std::stack<size_type>(); }
32  bool empty() const
33  { return stack_.empty(); }
35  { std::fill(visited_.begin(), visited_.end(), 0); }
37  { const size_type v = stack_.top(); stack_.pop(); return v; }
38  unsigned char& visited(const size_type v)
39  { return visited_[v]; }
40  unsigned char visited(const size_type v) const
41  { return visited_[v]; }
42 
43 private:
44  std::vector<unsigned char> visited_;
45  std::stack<size_type> stack_;
46 };
47 
48 template<typename GRAPH, typename CALLBACK>
49 inline void
51  const GRAPH& g,
52  const std::size_t start_vertex,
53  CALLBACK& callback
54 )
55 {
57  depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data);
58 }
59 
60 template<typename GRAPH, typename CALLBACK, typename = typename std::enable_if<!std::is_lvalue_reference<CALLBACK>::value>::type>
61 inline void
63  const GRAPH& g,
64  const std::size_t start_vertex,
65  CALLBACK&& callback
66 )
67 {
69  depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data);
70 }
71 
72 template<typename GRAPH, typename CALLBACK>
73 inline void
75  const GRAPH& g,
76  const std::size_t start_vertex,
77  CALLBACK& callback,
79 )
80 {
81  depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data);
82 }
83 
84 template<typename GRAPH, typename CALLBACK, typename = typename std::enable_if<!std::is_lvalue_reference<CALLBACK>::value>::type>
85 inline void
87  const GRAPH& g,
88  const std::size_t start_vertex,
89  CALLBACK&& callback,
91 )
92 {
93  depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data);
94 }
95 
96 template<typename GRAPH, typename SUBGRAPH, typename CALLBACK>
97 inline void
99  const GRAPH& g,
100  const SUBGRAPH& subgraph_mask,
101  const std::size_t start_vertex,
102  CALLBACK& callback
103 )
104 {
106  depthFirstSearch(g, subgraph_mask, start_vertex, callback, data);
107 }
108 
109 template<typename GRAPH, typename SUBGRAPH, typename CALLBACK, typename = typename std::enable_if<!std::is_lvalue_reference<CALLBACK>::value>::type>
110 inline void
112  const GRAPH& g,
113  const SUBGRAPH& subgraph_mask,
114  const std::size_t start_vertex,
115  CALLBACK&& callback
116 )
117 {
119  depthFirstSearch(g, subgraph_mask, start_vertex, callback, data);
120 }
121 
122 template<typename GRAPH, typename SUBGRAPH, typename CALLBACK>
123 inline void
125  const GRAPH& g,
126  const SUBGRAPH& subgraph_mask,
127  const std::size_t start_vertex,
128  CALLBACK& callback,
130 )
131 {
132  assert(start_vertex < g.numberOfVertices());
133 
134  data.add(start_vertex);
135 
136  while(!data.empty())
137  {
138  auto v = data.next();
139 
140  if (!data.visited(v))
141  {
142  data.visited(v) = 1;
143 
144  bool proceed;
145  bool addNeighbors;
146 
147  callback(v, proceed, addNeighbors);
148 
149  if (!proceed)
150  {
151  data.clearStack();
152  return;
153  }
154 
155  if (addNeighbors)
156  {
157  auto e_it = g.edgesFromVertexBegin(v);
158  for(auto it = g.verticesFromVertexBegin(v); it != g.verticesFromVertexEnd(v); ++it, ++e_it)
159  if (!data.visited(*it) && subgraph_mask.vertex(*it) && subgraph_mask.edge(*e_it))
160  data.add(*it);
161  }
162  }
163  }
164 }
165 
166 template<typename GRAPH, typename SUBGRAPH, typename CALLBACK, typename = typename std::enable_if<!std::is_lvalue_reference<CALLBACK>::value>::type>
167 inline void
169  const GRAPH& g,
170  const SUBGRAPH& subgraph_mask,
171  const std::size_t start_vertex,
172  CALLBACK&& callback,
174 )
175 {
176  depthFirstSearch(g, subgraph_mask, start_vertex, callback, data);
177 }
178 
179 } // namespace graph
180 } // namespace andres
181 
182 #endif