Aleph-w  1.9
General library for algorithms and data structures
topological_sort.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 # ifndef TOPOLOGICAL_SORT_H
28 # define TOPOLOGICAL_SORT_H
29 
30 # include <tpl_dynListQueue.H>
31 # include <tpl_graph.H>
32 
33 namespace Aleph {
34 
35 
44  template <class GT,
45  template <typename, class> class Itor = Out_Iterator,
46  class SA = Dft_Show_Arc<GT>>
48 {
49  SA & sa;
50  const GT * gptr;
51 
52 public:
53 
54  Topological_Sort(SA && __sa = SA())
55  noexcept(std::is_nothrow_move_assignable<SA>::value)
56  : sa(__sa), gptr(nullptr) { /* empty */ }
57 
58  Topological_Sort(SA & __sa)
59  noexcept(std::is_nothrow_copy_assignable<SA>::value)
60  : sa(__sa), gptr(nullptr) { /* empty */ }
61 
62 private:
63 
64  template <template <class> class List>
65  void topological_sort(typename GT::Node * curr,
66  List<typename GT::Node*> & list)
67  {
68  assert(gptr != nullptr);
69 
70  if (IS_NODE_VISITED(curr, Depth_First))
71  return;
72 
73  NODE_BITS(curr).set_bit(Depth_First, 1); // marcarlo como visitado
74 
75  const auto & n = gptr->get_num_nodes();
76 
77  // visitar recursivamente en sufijo los nodos adyacentes a curr
78  for (Itor<GT,SA> it(curr,sa); it.has_curr() and list.size() < n; it.next_ne())
79  topological_sort(it.get_tgt_node_ne(), list);
80 
81  list.insert(curr); // inserción sufija de nodo que devino sumidero
82  }
83 
84 public:
85 
95  template <template <class> class List>
96  List<typename GT::Node*> perform (const GT & g)
97  {
98  g.reset_bit_nodes(Depth_First); // iniciar bit de marca de visita en nodos
99 
100  gptr = &g;
101  List<typename GT::Node*> list;
102 
103  // recorrer todos los nodos
104  const auto & n = gptr->get_num_nodes();
105  for (auto it = g.get_node_it(); it.has_curr() and list.size() < n;
106  it.next_ne())
107  {
108  auto curr = it.get_current_node_ne();
109  if (not IS_NODE_VISITED(curr, Depth_First))
110  topological_sort(curr, list);
111  }
112 
113  return list;
114  }
115 
118  void operator () (const GT & g, DynDlist<typename GT::Node*> & list)
119  {
120  perform<DynDlist>(g).swap(list);
121  }
122 };
123 
133  template <class GT,
134  template <typename, class> class Itor = Out_Iterator,
135  class SA = Dft_Show_Arc<GT>>
137 {
138  SA & sa;
139 
140 public:
141 
142  Q_Topological_Sort(SA && __sa = SA())
143  noexcept(std::is_nothrow_move_assignable<SA>::value)
144  : sa(__sa) { /* empty */ }
145 
146  Q_Topological_Sort(SA & __sa)
147  noexcept(std::is_nothrow_copy_assignable<SA>::value)
148  : sa(__sa) { /* empty */ }
149 
161  template <template <class> class List>
162  List<typename GT::Node*> perform (const GT & g)
163  {
164  g.reset_counter_nodes();
165 
166  List<typename GT::Node*> list;
167 
168  // recorra todos los arcos y contar grados de entrada
169  for (Arc_Iterator<GT,SA> it(g, sa); it.has_curr(); it.next_ne())
170  NODE_COUNTER(it.get_tgt_node_ne())++;
171 
172  // buscar nodos con grado de entrada 0 y meterlos en cola
173  DynListQueue<typename GT::Node*> q; // cola de fuentes
174  for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
175  {
176  auto p = it.get_current_node_ne();
177  if (NODE_COUNTER(p) == 0) // ¿es un nodo fuente?
178  q.put(p); // sí ==> colocarlo en la cola
179  }
180 
181  while (not q.is_empty())
182  {
183  auto p = q.get(); // saque último fuente
184 
185  assert(NODE_COUNTER(p) == 0);
186 
187  list.append(p); // insértelo en el orden topológico
188 
189  // decrementar grado de entrada de cada nodo adyacente a p
190  for (Itor<GT, SA> it(p, sa); it.has_curr(); it.next_ne())
191  {
192  auto tgt = it.get_tgt_node_ne();
193  if (--NODE_COUNTER(tgt) == 0) // ¿tgt deviene fuente?
194  q.put(tgt); // sí ==> colóquelo en la cola
195  }
196  }
197 
198  return list;
199  }
200 
213  template <template <class> class RankList = DynList,
214  template <class> class List = DynList>
215  RankList<List<typename GT::Node*>> ranks(const GT & g)
216  {
217  g.reset_counter_nodes();
218 
219  // recorra todos los nodos para contabilizar grado de entrada
220  for (typename GT::Node_Iterator i(g); i.has_curr(); i.next_ne())
221  for (Itor<GT, SA> j(i.get_current_node_ne(), sa);
222  j.has_curr(); j.next_ne())
223  NODE_COUNTER(j.get_tgt_node())++;
224 
225  // revisar nodos con grado de entrada 0 y meterlos en cola
226  DynListQueue<typename GT::Node*> q; // cola de fuentes
227  for (typename GT::Node_Iterator it(g); it.has_curr(); it.next_ne())
228  {
229  auto p = it.get_current_node_ne();
230  if (NODE_COUNTER(p) == 0) // ¿es un nodo fuente?
231  q.put(p); // sí ==> colocarlo en la cola
232  }
233 
234  RankList<List<typename GT::Node*>> ranks; // valor de retorno
235  while (not q.is_empty())
236  {
237  List<typename GT::Node*> rank;
239 
240  while (not q.is_empty()) // saca todos los nodos del nivel i
241  {
242  auto p = q.get(); // saque último fuente
243  rank.append(p); // insértelo en el rango topológico
244 
245  // decrementar grado entrada de cada nodo adyacente a p
246  for (Itor<GT, SA> it(p, sa); it.has_curr(); it.next_ne())
247  {
248  auto tgt = it.get_tgt_node_ne();
249  if (--NODE_COUNTER(tgt) == 0) // ¿tgt deviene fuente?
250  aq.put(tgt); // sí ==> colóquelo en cola auxiliar
251  }
252  }
253 
254  ranks.append(std::move(rank));
255  q.swap(aq);
256  assert(aq.is_empty());
257  }
258 
259  return ranks;
260  }
261 
263  {
264  this->ranks<>(g).swap(list);
265  }
266 
268  {
269  this->ranks<DynList>(g).swap(list);
270  }
271 
274  {
275  this->perform<DynDlist>(g).swap(list);
276  }
277 };
278 
279 } // end namespace Aleph
280 
281 # endif // TOPOLOGICAL_SORT_H
Definition: topological_sort.H:47
Definition: tpl_graph.H:1225
void operator()(const GT &g, DynDlist< typename GT::Node *> &list)
Definition: topological_sort.H:118
Definition: topological_sort.H:136
bool is_empty() const noexcept
rioReturn true if this is empty
Definition: tpl_dynListQueue.H:112
Definition: tpl_dynDlist.H:51
#define IS_NODE_VISITED(p, bit)
Definition: aleph-graph.H:327
RankList< List< typename GT::Node * > > ranks(const GT &g)
Definition: topological_sort.H:215
Definition: tpl_dynListQueue.H:50
#define NODE_COUNTER(p)
Definition: aleph-graph.H:311
Definition: ah-comb.H:35
void swap(DynListQueue &__q) noexcept
Swap this with __q in constant time.
Definition: tpl_dynListQueue.H:65
List< typename GT::Node * > perform(const GT &g)
Definition: topological_sort.H:96
Definition: tpl_graph.H:1063
Definition: tpl_graph.H:1796
#define NODE_BITS(p)
Definition: aleph-graph.H:305
Definition: ahDry.H:41
T get()
Definition: tpl_dynListQueue.H:165
Definition: List.H:49
T & put(const T &data)
The type of element.
Definition: tpl_dynListQueue.H:125
List< typename GT::Node * > perform(const GT &g)
Definition: topological_sort.H:162

Leandro Rabindranath León