src/work/marci/bfs_dfs.h
author deba
Wed, 08 Sep 2004 12:06:45 +0000 (2004-09-08)
changeset 822 88226d9fe821
parent 774 4297098d9677
child 921 818510fa3d99
permissions -rw-r--r--
The MapFactories have been removed from the code because
if we use macros then they increases only the complexity.

The pair iterators of the maps are separeted from the maps.

Some macros and comments has been changed.
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