src/work/marci/bfs_dfs.h
author marci
Tue, 11 May 2004 12:09:06 +0000
changeset 605 b3c57602c516
parent 602 580b329c2a0c
child 615 b6b31b75b522
permissions -rw-r--r--
docs
marci@602
     1
// -*- c++ -*-
marci@602
     2
#ifndef HUGO_BFS_DFS_H
marci@602
     3
#define HUGO_BFS_DFS_H
marci@602
     4
marci@604
     5
// ///\ingroup gwrappers
marci@604
     6
///\file
marci@604
     7
///\brief Bfs and dfs iterators.
marci@604
     8
///
marci@604
     9
///This file contains bfs and dfs iterator classes.
marci@604
    10
///
marci@604
    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@602
    24
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@602
    25
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@602
    26
  class BfsIterator {
marci@602
    27
  protected:
marci@602
    28
    typedef typename Graph::Node Node;
marci@602
    29
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@602
    30
    const Graph* graph;
marci@602
    31
    std::queue<Node> bfs_queue;
marci@602
    32
    ReachedMap& reached;
marci@602
    33
    bool b_node_newly_reached;
marci@602
    34
    OutEdgeIt actual_edge;
marci@602
    35
    bool own_reached_map;
marci@602
    36
  public:
marci@602
    37
    /// In that constructor \c _reached have to be a reference 
marci@602
    38
    /// for a bool Node-map. The algorithm will search in a bfs order for 
marci@602
    39
    /// the nodes which are \c false initially
marci@602
    40
    BfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@602
    41
      graph(&_graph), reached(_reached), 
marci@602
    42
      own_reached_map(false) { }
marci@602
    43
    /// The same as above, but the map storing the reached nodes 
marci@602
    44
    /// is constructed dynamically to everywhere false.
marci@602
    45
    BfsIterator(const Graph& _graph) : 
marci@602
    46
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@602
    47
      own_reached_map(true) { }
marci@604
    48
    /// The map storing the reached nodes have to be destroyed if 
marci@602
    49
    /// it was constructed dynamically
marci@602
    50
    ~BfsIterator() { if (own_reached_map) delete &reached; }
marci@602
    51
    /// This method markes \c s reached.
marci@602
    52
    /// If the queue is empty, then \c s is pushed in the bfs queue 
marci@602
    53
    /// and the first out-edge is processed.
marci@602
    54
    /// If the queue is not empty, then \c s is simply pushed.
marci@602
    55
    void pushAndSetReached(Node s) { 
marci@602
    56
      reached.set(s, true);
marci@602
    57
      if (bfs_queue.empty()) {
marci@602
    58
	bfs_queue.push(s);
marci@602
    59
	graph->first(actual_edge, s);
marci@602
    60
	if (graph->valid(actual_edge)) { 
marci@602
    61
	  Node w=graph->bNode(actual_edge);
marci@602
    62
	  if (!reached[w]) {
marci@602
    63
	    bfs_queue.push(w);
marci@602
    64
	    reached.set(w, true);
marci@602
    65
	    b_node_newly_reached=true;
marci@602
    66
	  } else {
marci@602
    67
	    b_node_newly_reached=false;
marci@602
    68
	  }
marci@602
    69
	} 
marci@602
    70
      } else {
marci@602
    71
	bfs_queue.push(s);
marci@602
    72
      }
marci@602
    73
    }
marci@602
    74
    /// As \c BfsIterator<Graph, ReachedMap> works as an edge-iterator, 
marci@602
    75
    /// its \c operator++() iterates on the edges in a bfs order.
marci@602
    76
    BfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@602
    77
    operator++() { 
marci@602
    78
      if (graph->valid(actual_edge)) { 
marci@602
    79
	graph->next(actual_edge);
marci@602
    80
	if (graph->valid(actual_edge)) {
marci@602
    81
	  Node w=graph->bNode(actual_edge);
marci@602
    82
	  if (!reached[w]) {
marci@602
    83
	    bfs_queue.push(w);
marci@602
    84
	    reached.set(w, true);
marci@602
    85
	    b_node_newly_reached=true;
marci@602
    86
	  } else {
marci@602
    87
	    b_node_newly_reached=false;
marci@602
    88
	  }
marci@602
    89
	}
marci@602
    90
      } else {
marci@602
    91
	bfs_queue.pop(); 
marci@602
    92
	if (!bfs_queue.empty()) {
marci@602
    93
	  graph->first(actual_edge, bfs_queue.front());
marci@602
    94
	  if (graph->valid(actual_edge)) {
marci@602
    95
	    Node w=graph->bNode(actual_edge);
marci@602
    96
	    if (!reached[w]) {
marci@602
    97
	      bfs_queue.push(w);
marci@602
    98
	      reached.set(w, true);
marci@602
    99
	      b_node_newly_reached=true;
marci@602
   100
	    } else {
marci@602
   101
	      b_node_newly_reached=false;
marci@602
   102
	    }
marci@602
   103
	  }
marci@602
   104
	}
marci@602
   105
      }
marci@602
   106
      return *this;
marci@602
   107
    }
marci@602
   108
    ///
marci@602
   109
    bool finished() const { return bfs_queue.empty(); }
marci@602
   110
    /// The conversion operator makes for converting the bfs-iterator 
marci@602
   111
    /// to an \c out-edge-iterator.
marci@602
   112
    ///\bug Edge have to be in HUGO 0.2
marci@602
   113
    operator OutEdgeIt() const { return actual_edge; }
marci@602
   114
    ///
marci@602
   115
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@602
   116
    ///
marci@602
   117
    bool isANodeExamined() const { return !(graph->valid(actual_edge)); }
marci@602
   118
    ///
marci@602
   119
    Node aNode() const { return bfs_queue.front(); }
marci@602
   120
    ///
marci@602
   121
    Node bNode() const { return graph->bNode(actual_edge); }
marci@602
   122
    ///
marci@602
   123
    const ReachedMap& getReachedMap() const { return reached; }
marci@602
   124
    ///
marci@602
   125
    const std::queue<Node>& getBfsQueue() const { return bfs_queue; }
marci@602
   126
  };  
marci@602
   127
marci@602
   128
  /// Bfs searches for the nodes wich are not marked in 
marci@602
   129
  /// \c reached_map
marci@602
   130
  /// Reached have to work as a read-write bool Node-map, 
marci@602
   131
  /// Pred is a write Edge Node-map and
marci@602
   132
  /// Dist is a read-write int Node-map, have to be. 
marci@602
   133
  ///\todo In fact onsly simple operations requirement are needed for 
marci@602
   134
  /// Dist::Value.
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@602
   181
    ///
marci@602
   182
    const PredMap& getPredMap() const { return pred; }
marci@602
   183
    ///
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@602
   190
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@602
   191
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@602
   192
  class DfsIterator {
marci@602
   193
  protected:
marci@602
   194
    typedef typename Graph::Node Node;
marci@602
   195
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@602
   196
    const Graph* graph;
marci@602
   197
    std::stack<OutEdgeIt> dfs_stack;
marci@602
   198
    bool b_node_newly_reached;
marci@602
   199
    OutEdgeIt actual_edge;
marci@602
   200
    Node actual_node;
marci@602
   201
    ReachedMap& reached;
marci@602
   202
    bool own_reached_map;
marci@602
   203
  public:
marci@602
   204
    /// In that constructor \c _reached have to be a reference 
marci@602
   205
    /// for a bool Node-map. The algorithm will search in a dfs order for 
marci@602
   206
    /// the nodes which are \c false initially
marci@602
   207
    DfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@602
   208
      graph(&_graph), reached(_reached), 
marci@602
   209
      own_reached_map(false) { }
marci@602
   210
    /// The same as above, but the map of reached nodes is 
marci@602
   211
    /// constructed dynamically 
marci@602
   212
    /// to everywhere false.
marci@602
   213
    DfsIterator(const Graph& _graph) : 
marci@602
   214
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@602
   215
      own_reached_map(true) { }
marci@602
   216
    ~DfsIterator() { if (own_reached_map) delete &reached; }
marci@602
   217
    /// This method markes s reached and first out-edge is processed.
marci@602
   218
    void pushAndSetReached(Node s) { 
marci@602
   219
      actual_node=s;
marci@602
   220
      reached.set(s, true);
marci@602
   221
      OutEdgeIt e;
marci@602
   222
      graph->first(e, s);
marci@602
   223
      dfs_stack.push(e); 
marci@602
   224
    }
marci@602
   225
    /// As \c DfsIterator<Graph, ReachedMap> works as an edge-iterator, 
marci@602
   226
    /// its \c operator++() iterates on the edges in a dfs order.
marci@602
   227
    DfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@602
   228
    operator++() { 
marci@602
   229
      actual_edge=dfs_stack.top();
marci@602
   230
      //actual_node=G.aNode(actual_edge);
marci@602
   231
      if (graph->valid(actual_edge)/*.valid()*/) { 
marci@602
   232
	Node w=graph->bNode(actual_edge);
marci@602
   233
	actual_node=w;
marci@602
   234
	if (!reached[w]) {
marci@602
   235
	  OutEdgeIt e;
marci@602
   236
	  graph->first(e, w);
marci@602
   237
	  dfs_stack.push(e);
marci@602
   238
	  reached.set(w, true);
marci@602
   239
	  b_node_newly_reached=true;
marci@602
   240
	} else {
marci@602
   241
	  actual_node=graph->aNode(actual_edge);
marci@602
   242
	  graph->next(dfs_stack.top());
marci@602
   243
	  b_node_newly_reached=false;
marci@602
   244
	}
marci@602
   245
      } else {
marci@602
   246
	//actual_node=G.aNode(dfs_stack.top());
marci@602
   247
	dfs_stack.pop();
marci@602
   248
      }
marci@602
   249
      return *this;
marci@602
   250
    }
marci@602
   251
    ///
marci@602
   252
    bool finished() const { return dfs_stack.empty(); }
marci@602
   253
    ///
marci@602
   254
    operator OutEdgeIt() const { return actual_edge; }
marci@602
   255
    ///
marci@602
   256
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@602
   257
    ///
marci@602
   258
    bool isANodeExamined() const { return !(graph->valid(actual_edge)); }
marci@602
   259
    ///
marci@602
   260
    Node aNode() const { return actual_node; /*FIXME*/}
marci@602
   261
    ///
marci@602
   262
    Node bNode() const { return graph->bNode(actual_edge); }
marci@602
   263
    ///
marci@602
   264
    const ReachedMap& getReachedMap() const { return reached; }
marci@602
   265
    ///
marci@602
   266
    const std::stack<OutEdgeIt>& getDfsStack() const { return dfs_stack; }
marci@602
   267
  };
marci@602
   268
marci@602
   269
  /// Dfs searches for the nodes wich are not marked in 
marci@602
   270
  /// \c reached_map
marci@602
   271
  /// Reached is a read-write bool Node-map, 
marci@602
   272
  /// Pred is a write Node-map, have to be.
marci@602
   273
  template <typename Graph, 
marci@602
   274
	    typename ReachedMap=typename Graph::template NodeMap<bool>, 
marci@602
   275
	    typename PredMap
marci@602
   276
	    =typename Graph::template NodeMap<typename Graph::Edge> > 
marci@602
   277
  class Dfs : public DfsIterator<Graph, ReachedMap> {
marci@602
   278
    typedef DfsIterator<Graph, ReachedMap> Parent;
marci@602
   279
  protected:
marci@602
   280
    typedef typename Parent::Node Node;
marci@602
   281
    PredMap& pred;
marci@602
   282
  public:
marci@602
   283
    /// The algorithm will search in a dfs order for 
marci@602
   284
    /// the nodes which are \c false initially. 
marci@602
   285
    /// The constructor makes no initial changes on the maps.
marci@602
   286
    Dfs<Graph, ReachedMap, PredMap>(const Graph& _graph, ReachedMap& _reached, PredMap& _pred) : DfsIterator<Graph, ReachedMap>(_graph, _reached), pred(&_pred) { }
marci@602
   287
    /// \c s is marked to be reached and pushed in the bfs queue.
marci@602
   288
    /// If the queue is empty, then the first out-edge is processed.
marci@602
   289
    /// If \c s was not marked previously, then 
marci@602
   290
    /// in addition its pred is set to be \c INVALID. 
marci@602
   291
    /// if \c s was marked previuosly, then it is simply pushed.
marci@602
   292
    void push(Node s) { 
marci@602
   293
      if (this->reached[s]) {
marci@602
   294
	Parent::pushAndSetReached(s);
marci@602
   295
      } else {
marci@602
   296
	Parent::pushAndSetReached(s);
marci@602
   297
	pred.set(s, INVALID);
marci@602
   298
      }
marci@602
   299
    }
marci@602
   300
    /// A bfs is processed from \c s.
marci@602
   301
    void run(Node s) {
marci@602
   302
      push(s);
marci@602
   303
      while (!this->finished()) this->operator++();
marci@602
   304
    }
marci@602
   305
    /// Beside the dfs iteration, \c pred is saved in a 
marci@602
   306
    /// newly reached node. 
marci@604
   307
    Dfs<Graph, ReachedMap, PredMap>& operator++() {
marci@602
   308
      Parent::operator++();
marci@602
   309
      if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) 
marci@602
   310
      {
marci@602
   311
	pred.set(this->bNode(), this->actual_edge);
marci@602
   312
      }
marci@602
   313
      return *this;
marci@602
   314
    }
marci@602
   315
    ///
marci@602
   316
    const PredMap& getPredMap() const { return pred; }
marci@602
   317
  };
marci@602
   318
marci@602
   319
marci@602
   320
} // namespace hugo
marci@602
   321
marci@602
   322
#endif //HUGO_BFS_DFS_H