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