src/work/marci/bfs_dfs.h
author marci
Tue, 21 Sep 2004 11:54:20 +0000
changeset 892 004636791dd7
parent 774 4297098d9677
child 921 818510fa3d99
permissions -rw-r--r--
graph_wrappers now pass the tests.
marci@602
     1
// -*- c++ -*-
marci@602
     2
#ifndef HUGO_BFS_DFS_H
marci@602
     3
#define HUGO_BFS_DFS_H
marci@602
     4
marci@615
     5
/// \ingroup galgs
marci@615
     6
/// \file
marci@615
     7
/// \brief Bfs and dfs iterators.
marci@604
     8
///
marci@615
     9
/// This file contains bfs and dfs iterator classes.
marci@604
    10
///
marci@615
    11
// /// \author Marton Makai
marci@604
    12
marci@602
    13
#include <queue>
marci@602
    14
#include <stack>
marci@602
    15
#include <utility>
marci@602
    16
marci@602
    17
#include <hugo/invalid.h>
marci@602
    18
marci@602
    19
namespace hugo {
marci@602
    20
marci@602
    21
  /// Bfs searches for the nodes wich are not marked in 
marci@602
    22
  /// \c reached_map
marci@650
    23
  /// Reached have to be a read-write bool node-map.
marci@615
    24
  /// \ingroup galgs
marci@602
    25
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@602
    26
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@602
    27
  class BfsIterator {
marci@602
    28
  protected:
marci@602
    29
    typedef typename Graph::Node Node;
marci@777
    30
    typedef typename Graph::Edge Edge;
marci@602
    31
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@602
    32
    const Graph* graph;
marci@602
    33
    std::queue<Node> bfs_queue;
marci@602
    34
    ReachedMap& reached;
marci@602
    35
    bool b_node_newly_reached;
marci@777
    36
    Edge actual_edge;
marci@602
    37
    bool own_reached_map;
marci@602
    38
  public:
marci@602
    39
    /// In that constructor \c _reached have to be a reference 
marci@650
    40
    /// for a bool bode-map. The algorithm will search for the 
marci@650
    41
    /// initially \c false nodes 
marci@650
    42
    /// in a bfs order.
marci@602
    43
    BfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@602
    44
      graph(&_graph), reached(_reached), 
marci@602
    45
      own_reached_map(false) { }
marci@602
    46
    /// The same as above, but the map storing the reached nodes 
marci@602
    47
    /// is constructed dynamically to everywhere false.
marci@650
    48
    /// \deprecated
marci@602
    49
    BfsIterator(const Graph& _graph) : 
marci@602
    50
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@602
    51
      own_reached_map(true) { }
marci@604
    52
    /// The map storing the reached nodes have to be destroyed if 
marci@602
    53
    /// it was constructed dynamically
marci@602
    54
    ~BfsIterator() { if (own_reached_map) delete &reached; }
marci@602
    55
    /// This method markes \c s reached.
marci@602
    56
    /// If the queue is empty, then \c s is pushed in the bfs queue 
marci@602
    57
    /// and the first out-edge is processed.
marci@602
    58
    /// If the queue is not empty, then \c s is simply pushed.
marci@777
    59
    BfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& pushAndSetReached(Node s) { 
marci@602
    60
      reached.set(s, true);
marci@602
    61
      if (bfs_queue.empty()) {
marci@602
    62
	bfs_queue.push(s);
marci@777
    63
	actual_edge=OutEdgeIt(*graph, s);
marci@777
    64
	//graph->first(actual_edge, s);
alpar@774
    65
	if (actual_edge!=INVALID) { 
alpar@774
    66
	  Node w=graph->head(actual_edge);
marci@602
    67
	  if (!reached[w]) {
marci@602
    68
	    bfs_queue.push(w);
marci@602
    69
	    reached.set(w, true);
marci@602
    70
	    b_node_newly_reached=true;
marci@602
    71
	  } else {
marci@602
    72
	    b_node_newly_reached=false;
marci@602
    73
	  }
marci@602
    74
	} 
marci@602
    75
      } else {
marci@602
    76
	bfs_queue.push(s);
marci@602
    77
      }
marci@777
    78
      return *this;
marci@602
    79
    }
marci@602
    80
    /// As \c BfsIterator<Graph, ReachedMap> works as an edge-iterator, 
marci@602
    81
    /// its \c operator++() iterates on the edges in a bfs order.
marci@602
    82
    BfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@602
    83
    operator++() { 
alpar@774
    84
      if (actual_edge!=INVALID) { 
marci@777
    85
	actual_edge=++OutEdgeIt(*graph, actual_edge);
marci@777
    86
	//++actual_edge;
alpar@774
    87
	if (actual_edge!=INVALID) {
alpar@774
    88
	  Node w=graph->head(actual_edge);
marci@602
    89
	  if (!reached[w]) {
marci@602
    90
	    bfs_queue.push(w);
marci@602
    91
	    reached.set(w, true);
marci@602
    92
	    b_node_newly_reached=true;
marci@602
    93
	  } else {
marci@602
    94
	    b_node_newly_reached=false;
marci@602
    95
	  }
marci@602
    96
	}
marci@602
    97
      } else {
marci@602
    98
	bfs_queue.pop(); 
marci@602
    99
	if (!bfs_queue.empty()) {
marci@777
   100
	  actual_edge=OutEdgeIt(*graph, bfs_queue.front());
marci@777
   101
	  //graph->first(actual_edge, bfs_queue.front());
alpar@774
   102
	  if (actual_edge!=INVALID) {
alpar@774
   103
	    Node w=graph->head(actual_edge);
marci@602
   104
	    if (!reached[w]) {
marci@602
   105
	      bfs_queue.push(w);
marci@602
   106
	      reached.set(w, true);
marci@602
   107
	      b_node_newly_reached=true;
marci@602
   108
	    } else {
marci@602
   109
	      b_node_newly_reached=false;
marci@602
   110
	    }
marci@602
   111
	  }
marci@602
   112
	}
marci@602
   113
      }
marci@602
   114
      return *this;
marci@602
   115
    }
marci@646
   116
    /// Returns true iff the algorithm is finished.
marci@602
   117
    bool finished() const { return bfs_queue.empty(); }
marci@602
   118
    /// The conversion operator makes for converting the bfs-iterator 
marci@602
   119
    /// to an \c out-edge-iterator.
marci@602
   120
    ///\bug Edge have to be in HUGO 0.2
marci@777
   121
    operator Edge() const { return actual_edge; }
marci@646
   122
    /// Returns if b-node has been reached just now.
marci@602
   123
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@646
   124
    /// Returns if a-node is examined.
alpar@774
   125
    bool isANodeExamined() const { return actual_edge==INVALID; }
marci@646
   126
    /// Returns a-node of the actual edge, so does if the edge is invalid.
marci@777
   127
    Node tail() const { return bfs_queue.front(); }
marci@646
   128
    /// \pre The actual edge have to be valid.
marci@777
   129
    Node head() const { return graph->head(actual_edge); }
marci@615
   130
    /// Guess what?
marci@650
   131
    /// \deprecated 
marci@602
   132
    const ReachedMap& getReachedMap() const { return reached; }
marci@615
   133
    /// Guess what?
marci@650
   134
    /// \deprecated
marci@602
   135
    const std::queue<Node>& getBfsQueue() const { return bfs_queue; }
marci@615
   136
  };
marci@602
   137
marci@602
   138
  /// Bfs searches for the nodes wich are not marked in 
marci@602
   139
  /// \c reached_map
marci@602
   140
  /// Reached have to work as a read-write bool Node-map, 
marci@650
   141
  /// Pred is a write edge node-map and
marci@650
   142
  /// Dist is a read-write node-map of integral value, have to be. 
marci@615
   143
  /// \ingroup galgs
marci@602
   144
  template <typename Graph, 
marci@602
   145
	    typename ReachedMap=typename Graph::template NodeMap<bool>, 
marci@602
   146
	    typename PredMap
marci@602
   147
	    =typename Graph::template NodeMap<typename Graph::Edge>, 
marci@602
   148
	    typename DistMap=typename Graph::template NodeMap<int> > 
marci@602
   149
  class Bfs : public BfsIterator<Graph, ReachedMap> {
marci@602
   150
    typedef BfsIterator<Graph, ReachedMap> Parent;
marci@602
   151
  protected:
marci@602
   152
    typedef typename Parent::Node Node;
marci@602
   153
    PredMap& pred;
marci@602
   154
    DistMap& dist;
marci@602
   155
  public:
marci@602
   156
    /// The algorithm will search in a bfs order for 
marci@602
   157
    /// the nodes which are \c false initially. 
marci@602
   158
    /// The constructor makes no initial changes on the maps.
athos@671
   159
    Bfs<Graph, ReachedMap, PredMap, DistMap>(const Graph& _graph, ReachedMap& _reached, PredMap& _pred, DistMap& _dist) : 
athos@671
   160
      BfsIterator<Graph, ReachedMap>(_graph, _reached), 
athos@671
   161
      pred(_pred), dist(_dist) { }
marci@602
   162
    /// \c s is marked to be reached and pushed in the bfs queue.
marci@602
   163
    /// If the queue is empty, then the first out-edge is processed.
marci@602
   164
    /// If \c s was not marked previously, then 
marci@602
   165
    /// in addition its pred is set to be \c INVALID, and dist to \c 0. 
marci@602
   166
    /// if \c s was marked previuosly, then it is simply pushed.
marci@777
   167
    Bfs<Graph, ReachedMap, PredMap, DistMap>& push(Node s) { 
marci@602
   168
      if (this->reached[s]) {
marci@602
   169
	Parent::pushAndSetReached(s);
marci@602
   170
      } else {
marci@602
   171
	Parent::pushAndSetReached(s);
marci@602
   172
	pred.set(s, INVALID);
marci@602
   173
	dist.set(s, 0);
marci@602
   174
      }
marci@777
   175
      return *this;
marci@602
   176
    }
marci@602
   177
    /// A bfs is processed from \c s.
marci@777
   178
    Bfs<Graph, ReachedMap, PredMap, DistMap>& run(Node s) {
marci@602
   179
      push(s);
marci@602
   180
      while (!this->finished()) this->operator++();
marci@777
   181
      return *this;
marci@602
   182
    }
marci@602
   183
    /// Beside the bfs iteration, \c pred and \dist are saved in a 
marci@602
   184
    /// newly reached node. 
marci@604
   185
    Bfs<Graph, ReachedMap, PredMap, DistMap>& operator++() {
marci@602
   186
      Parent::operator++();
marci@602
   187
      if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) 
marci@602
   188
      {
marci@777
   189
	pred.set(this->head(), this->actual_edge);
marci@777
   190
	dist.set(this->head(), dist[this->tail()]);
marci@602
   191
      }
marci@602
   192
      return *this;
marci@602
   193
    }
marci@615
   194
    /// Guess what?
marci@650
   195
    /// \deprecated 
marci@602
   196
    const PredMap& getPredMap() const { return pred; }
marci@615
   197
    /// Guess what?
marci@650
   198
    /// \deprecated
marci@602
   199
    const DistMap& getDistMap() const { return dist; }
marci@602
   200
  };
marci@602
   201
marci@602
   202
  /// Dfs searches for the nodes wich are not marked in 
marci@602
   203
  /// \c reached_map
marci@602
   204
  /// Reached have to be a read-write bool Node-map.
marci@615
   205
  /// \ingroup galgs
marci@602
   206
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@602
   207
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@602
   208
  class DfsIterator {
marci@602
   209
  protected:
marci@602
   210
    typedef typename Graph::Node Node;
marci@777
   211
    typedef typename Graph::Edge Edge;
marci@602
   212
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@602
   213
    const Graph* graph;
marci@602
   214
    std::stack<OutEdgeIt> dfs_stack;
marci@602
   215
    bool b_node_newly_reached;
marci@777
   216
    Edge actual_edge;
marci@602
   217
    Node actual_node;
marci@602
   218
    ReachedMap& reached;
marci@602
   219
    bool own_reached_map;
marci@602
   220
  public:
marci@602
   221
    /// In that constructor \c _reached have to be a reference 
marci@650
   222
    /// for a bool node-map. The algorithm will search in a dfs order for 
marci@602
   223
    /// the nodes which are \c false initially
marci@602
   224
    DfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@602
   225
      graph(&_graph), reached(_reached), 
marci@602
   226
      own_reached_map(false) { }
marci@602
   227
    /// The same as above, but the map of reached nodes is 
marci@602
   228
    /// constructed dynamically 
marci@602
   229
    /// to everywhere false.
marci@602
   230
    DfsIterator(const Graph& _graph) : 
marci@602
   231
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@602
   232
      own_reached_map(true) { }
marci@602
   233
    ~DfsIterator() { if (own_reached_map) delete &reached; }
marci@602
   234
    /// This method markes s reached and first out-edge is processed.
marci@777
   235
    DfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& pushAndSetReached(Node s) { 
marci@602
   236
      actual_node=s;
marci@602
   237
      reached.set(s, true);
marci@777
   238
      OutEdgeIt e(*graph, s);
marci@777
   239
      //graph->first(e, s);
marci@602
   240
      dfs_stack.push(e); 
marci@777
   241
      return *this;
marci@602
   242
    }
marci@602
   243
    /// As \c DfsIterator<Graph, ReachedMap> works as an edge-iterator, 
marci@602
   244
    /// its \c operator++() iterates on the edges in a dfs order.
marci@602
   245
    DfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@602
   246
    operator++() { 
marci@602
   247
      actual_edge=dfs_stack.top();
alpar@774
   248
      if (actual_edge!=INVALID/*.valid()*/) { 
alpar@774
   249
	Node w=graph->head(actual_edge);
marci@602
   250
	actual_node=w;
marci@602
   251
	if (!reached[w]) {
marci@777
   252
	  OutEdgeIt e(*graph, w);
marci@777
   253
	  //graph->first(e, w);
marci@602
   254
	  dfs_stack.push(e);
marci@602
   255
	  reached.set(w, true);
marci@602
   256
	  b_node_newly_reached=true;
marci@602
   257
	} else {
alpar@774
   258
	  actual_node=graph->tail(actual_edge);
alpar@774
   259
	  ++dfs_stack.top();
marci@602
   260
	  b_node_newly_reached=false;
marci@602
   261
	}
marci@602
   262
      } else {
marci@602
   263
	//actual_node=G.aNode(dfs_stack.top());
marci@602
   264
	dfs_stack.pop();
marci@602
   265
      }
marci@602
   266
      return *this;
marci@602
   267
    }
marci@646
   268
    /// Returns true iff the algorithm is finished.
marci@602
   269
    bool finished() const { return dfs_stack.empty(); }
marci@646
   270
    /// The conversion operator makes for converting the bfs-iterator 
marci@646
   271
    /// to an \c out-edge-iterator.
marci@646
   272
    ///\bug Edge have to be in HUGO 0.2
marci@777
   273
    operator Edge() const { return actual_edge; }
marci@646
   274
    /// Returns if b-node has been reached just now.
marci@602
   275
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@646
   276
    /// Returns if a-node is examined.
alpar@774
   277
    bool isANodeExamined() const { return actual_edge==INVALID; }
marci@646
   278
    /// Returns a-node of the actual edge, so does if the edge is invalid.
marci@777
   279
    Node tail() const { return actual_node; /*FIXME*/}
marci@646
   280
    /// Returns b-node of the actual edge. 
marci@646
   281
    /// \pre The actual edge have to be valid.
marci@777
   282
    Node head() const { return graph->head(actual_edge); }
marci@615
   283
    /// Guess what?
marci@650
   284
    /// \deprecated
marci@602
   285
    const ReachedMap& getReachedMap() const { return reached; }
marci@615
   286
    /// Guess what?
marci@650
   287
    /// \deprecated
marci@602
   288
    const std::stack<OutEdgeIt>& getDfsStack() const { return dfs_stack; }
marci@602
   289
  };
marci@602
   290
marci@602
   291
  /// Dfs searches for the nodes wich are not marked in 
marci@602
   292
  /// \c reached_map
marci@650
   293
  /// Reached is a read-write bool node-map, 
marci@650
   294
  /// Pred is a write node-map, have to be.
marci@615
   295
  /// \ingroup galgs
marci@602
   296
  template <typename Graph, 
marci@602
   297
	    typename ReachedMap=typename Graph::template NodeMap<bool>, 
marci@602
   298
	    typename PredMap
marci@602
   299
	    =typename Graph::template NodeMap<typename Graph::Edge> > 
marci@602
   300
  class Dfs : public DfsIterator<Graph, ReachedMap> {
marci@602
   301
    typedef DfsIterator<Graph, ReachedMap> Parent;
marci@602
   302
  protected:
marci@602
   303
    typedef typename Parent::Node Node;
marci@602
   304
    PredMap& pred;
marci@602
   305
  public:
marci@602
   306
    /// The algorithm will search in a dfs order for 
marci@602
   307
    /// the nodes which are \c false initially. 
marci@602
   308
    /// The constructor makes no initial changes on the maps.
athos@671
   309
    Dfs<Graph, ReachedMap, PredMap>(const Graph& _graph, ReachedMap& _reached, PredMap& _pred) : DfsIterator<Graph, ReachedMap>(_graph, _reached), pred(_pred) { }
marci@602
   310
    /// \c s is marked to be reached and pushed in the bfs queue.
marci@602
   311
    /// If the queue is empty, then the first out-edge is processed.
marci@602
   312
    /// If \c s was not marked previously, then 
marci@602
   313
    /// in addition its pred is set to be \c INVALID. 
marci@602
   314
    /// if \c s was marked previuosly, then it is simply pushed.
marci@777
   315
    Dfs<Graph, ReachedMap, PredMap>& push(Node s) { 
marci@602
   316
      if (this->reached[s]) {
marci@602
   317
	Parent::pushAndSetReached(s);
marci@602
   318
      } else {
marci@602
   319
	Parent::pushAndSetReached(s);
marci@602
   320
	pred.set(s, INVALID);
marci@602
   321
      }
marci@777
   322
      return *this;
marci@602
   323
    }
marci@602
   324
    /// A bfs is processed from \c s.
marci@777
   325
    Dfs<Graph, ReachedMap, PredMap>& run(Node s) {
marci@602
   326
      push(s);
marci@602
   327
      while (!this->finished()) this->operator++();
marci@777
   328
      return *this;
marci@602
   329
    }
marci@602
   330
    /// Beside the dfs iteration, \c pred is saved in a 
marci@602
   331
    /// newly reached node. 
marci@604
   332
    Dfs<Graph, ReachedMap, PredMap>& operator++() {
marci@602
   333
      Parent::operator++();
marci@602
   334
      if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) 
marci@602
   335
      {
marci@777
   336
	pred.set(this->head(), this->actual_edge);
marci@602
   337
      }
marci@602
   338
      return *this;
marci@602
   339
    }
marci@615
   340
    /// Guess what?
marci@650
   341
    /// \deprecated
marci@602
   342
    const PredMap& getPredMap() const { return pred; }
marci@602
   343
  };
marci@602
   344
marci@602
   345
marci@602
   346
} // namespace hugo
marci@602
   347
marci@602
   348
#endif //HUGO_BFS_DFS_H