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