src/work/marci/bfs_iterator.h
author marci
Fri, 07 May 2004 10:57:31 +0000
changeset 576 d00c33d07114
parent 448 510c53fd06cd
child 597 a6e2b02f496a
permissions -rw-r--r--
(none)
marci@301
     1
// -*- c++ -*-
marci@301
     2
#ifndef HUGO_BFS_ITERATOR_H
marci@301
     3
#define HUGO_BFS_ITERATOR_H
marci@301
     4
marci@301
     5
#include <queue>
marci@301
     6
#include <stack>
marci@301
     7
#include <utility>
marci@301
     8
marci@560
     9
#include <hugo/invalid.h>
marci@560
    10
marci@301
    11
namespace hugo {
marci@301
    12
marci@303
    13
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@303
    14
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@360
    15
  class BfsIterator {
marci@303
    16
  protected:
marci@303
    17
    typedef typename Graph::Node Node;
marci@303
    18
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@303
    19
    const Graph* graph;
marci@301
    20
    std::queue<Node> bfs_queue;
marci@301
    21
    ReachedMap& reached;
marci@301
    22
    bool b_node_newly_reached;
marci@301
    23
    OutEdgeIt actual_edge;
marci@301
    24
    bool own_reached_map;
marci@301
    25
  public:
marci@360
    26
    BfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@303
    27
      graph(&_graph), reached(_reached), 
marci@301
    28
      own_reached_map(false) { }
marci@360
    29
    BfsIterator(const Graph& _graph) : 
marci@303
    30
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@301
    31
      own_reached_map(true) { }
marci@360
    32
    ~BfsIterator() { if (own_reached_map) delete &reached; }
marci@448
    33
    /// This method markes s reached.
marci@448
    34
    /// If the queue is empty, then s is pushed in the bfs queue 
marci@448
    35
    /// and the first OutEdgeIt is processed.
marci@448
    36
    /// If the queue is not empty, then s is simply pushed.
marci@301
    37
    void pushAndSetReached(Node s) { 
marci@301
    38
      reached.set(s, true);
marci@301
    39
      if (bfs_queue.empty()) {
marci@301
    40
	bfs_queue.push(s);
marci@303
    41
	graph->first(actual_edge, s);
marci@303
    42
	if (graph->valid(actual_edge)) { 
marci@303
    43
	  Node w=graph->bNode(actual_edge);
marci@303
    44
	  if (!reached[w]) {
marci@301
    45
	    bfs_queue.push(w);
marci@301
    46
	    reached.set(w, true);
marci@301
    47
	    b_node_newly_reached=true;
marci@301
    48
	  } else {
marci@301
    49
	    b_node_newly_reached=false;
marci@301
    50
	  }
marci@301
    51
	} 
marci@301
    52
      } else {
marci@301
    53
	bfs_queue.push(s);
marci@301
    54
      }
marci@301
    55
    }
marci@448
    56
    /// As \c BfsIterator<Graph, ReachedMap> works as an edge-iterator, 
marci@448
    57
    /// its \c operator++() iterates on the edges in a bfs order.
marci@360
    58
    BfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@301
    59
    operator++() { 
marci@303
    60
      if (graph->valid(actual_edge)) { 
marci@303
    61
	graph->next(actual_edge);
marci@303
    62
	if (graph->valid(actual_edge)) {
marci@303
    63
	  Node w=graph->bNode(actual_edge);
marci@303
    64
	  if (!reached[w]) {
marci@301
    65
	    bfs_queue.push(w);
marci@301
    66
	    reached.set(w, true);
marci@301
    67
	    b_node_newly_reached=true;
marci@301
    68
	  } else {
marci@301
    69
	    b_node_newly_reached=false;
marci@301
    70
	  }
marci@301
    71
	}
marci@301
    72
      } else {
marci@301
    73
	bfs_queue.pop(); 
marci@301
    74
	if (!bfs_queue.empty()) {
marci@303
    75
	  graph->first(actual_edge, bfs_queue.front());
marci@303
    76
	  if (graph->valid(actual_edge)) {
marci@303
    77
	    Node w=graph->bNode(actual_edge);
marci@303
    78
	    if (!reached[w]) {
marci@301
    79
	      bfs_queue.push(w);
marci@301
    80
	      reached.set(w, true);
marci@301
    81
	      b_node_newly_reached=true;
marci@301
    82
	    } else {
marci@301
    83
	      b_node_newly_reached=false;
marci@301
    84
	    }
marci@301
    85
	  }
marci@301
    86
	}
marci@301
    87
      }
marci@301
    88
      return *this;
marci@301
    89
    }
marci@301
    90
    bool finished() const { return bfs_queue.empty(); }
marci@448
    91
    /// The conversion operator makes for converting the bfs-iterator 
marci@448
    92
    /// to an \c out-edge-iterator.
marci@409
    93
    operator OutEdgeIt() const { return actual_edge; }
marci@301
    94
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@303
    95
    bool isANodeExamined() const { return !(graph->valid(actual_edge)); }
marci@301
    96
    Node aNode() const { return bfs_queue.front(); }
marci@303
    97
    Node bNode() const { return graph->bNode(actual_edge); }
marci@301
    98
    const ReachedMap& getReachedMap() const { return reached; }
marci@301
    99
    const std::queue<Node>& getBfsQueue() const { return bfs_queue; }
marci@301
   100
  };  
marci@301
   101
marci@409
   102
  /// Bfs searches from s for the nodes wich are not marked in 
marci@448
   103
  /// \c reached_map
marci@448
   104
  /// Reached is a read-write bool-map, Pred is a write-nodemap 
marci@448
   105
  /// and dist is an rw-nodemap, have to be.
marci@409
   106
  template <typename Graph, 
marci@409
   107
	    typename ReachedMap=typename Graph::template NodeMap<bool>, 
marci@409
   108
	    typename PredMap
marci@409
   109
	    =typename Graph::template NodeMap<typename Graph::Edge>, 
marci@409
   110
	    typename DistMap=typename Graph::template NodeMap<int> > 
marci@409
   111
  class Bfs : public BfsIterator<Graph, ReachedMap> {
marci@409
   112
    typedef BfsIterator<Graph, ReachedMap> Parent;
marci@409
   113
  protected:
marci@409
   114
    typedef typename Parent::Node Node;
marci@409
   115
    PredMap& pred;
marci@409
   116
    DistMap& dist;
marci@409
   117
  public:
marci@409
   118
    Bfs<Graph, ReachedMap, PredMap, DistMap>(const Graph& _graph, ReachedMap& _reached, PredMap& _pred, DistMap& _dist) : BfsIterator<Graph, ReachedMap>(_graph, _reached), pred(&_pred), dist(&_dist) { }
marci@448
   119
    /// s is marked to be reached and pushed in the bfs queue.
marci@448
   120
    /// If the queue is empty, then the first out-edge is processed.
marci@448
   121
    /// If s was not marked previously, then 
marci@448
   122
    /// in addition its pred is set to be INVALID, and dist to 0. 
marci@448
   123
    /// if s was marked previuosly, then it is simply pushed.
marci@409
   124
    void push(Node s) { 
marci@409
   125
      if (this->reached[s]) {
marci@409
   126
	Parent::pushAndSetReached(s);
marci@409
   127
      } else {
marci@409
   128
	Parent::pushAndSetReached(s);
marci@409
   129
	pred.set(s, INVALID);
marci@409
   130
	dist.set(s, 0);
marci@409
   131
      }
marci@409
   132
    }
marci@448
   133
    /// A bfs is processed from s.
marci@409
   134
    void run(Node s) {
marci@409
   135
      push(s);
marci@409
   136
      while (!this->finished()) this->operator++();
marci@409
   137
    }
marci@409
   138
    Bfs<Graph, ReachedMap, PredMap, DistMap> operator++() {
marci@409
   139
      Parent::operator++();
marci@415
   140
      if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) 
marci@415
   141
      {
marci@415
   142
	pred.set(this->bNode(), this->actual_edge);
marci@415
   143
	dist.set(this->bNode(), dist[this->aNode()]);
marci@409
   144
      }
marci@409
   145
      return *this;
marci@409
   146
    }
marci@409
   147
    const PredMap& getPredMap() const { return pred; }
marci@409
   148
    const DistMap& getDistMap() const { return dist; }
marci@409
   149
  };
marci@409
   150
marci@303
   151
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@303
   152
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@360
   153
  class DfsIterator {
marci@303
   154
  protected:
marci@303
   155
    typedef typename Graph::Node Node;
marci@303
   156
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@303
   157
    const Graph* graph;
marci@301
   158
    std::stack<OutEdgeIt> dfs_stack;
marci@301
   159
    bool b_node_newly_reached;
marci@301
   160
    OutEdgeIt actual_edge;
marci@301
   161
    Node actual_node;
marci@301
   162
    ReachedMap& reached;
marci@301
   163
    bool own_reached_map;
marci@301
   164
  public:
marci@360
   165
    DfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@303
   166
      graph(&_graph), reached(_reached), 
marci@301
   167
      own_reached_map(false) { }
marci@360
   168
    DfsIterator(const Graph& _graph) : 
marci@303
   169
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@301
   170
      own_reached_map(true) { }
marci@360
   171
    ~DfsIterator() { if (own_reached_map) delete &reached; }
marci@301
   172
    void pushAndSetReached(Node s) { 
marci@301
   173
      actual_node=s;
marci@301
   174
      reached.set(s, true);
marci@301
   175
      OutEdgeIt e;
marci@303
   176
      graph->first(e, s);
marci@301
   177
      dfs_stack.push(e); 
marci@301
   178
    }
marci@360
   179
    DfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@301
   180
    operator++() { 
marci@301
   181
      actual_edge=dfs_stack.top();
marci@301
   182
      //actual_node=G.aNode(actual_edge);
marci@303
   183
      if (graph->valid(actual_edge)/*.valid()*/) { 
marci@303
   184
	Node w=graph->bNode(actual_edge);
marci@301
   185
	actual_node=w;
marci@303
   186
	if (!reached[w]) {
marci@301
   187
	  OutEdgeIt e;
marci@303
   188
	  graph->first(e, w);
marci@301
   189
	  dfs_stack.push(e);
marci@301
   190
	  reached.set(w, true);
marci@301
   191
	  b_node_newly_reached=true;
marci@301
   192
	} else {
marci@303
   193
	  actual_node=graph->aNode(actual_edge);
marci@303
   194
	  graph->next(dfs_stack.top());
marci@301
   195
	  b_node_newly_reached=false;
marci@301
   196
	}
marci@301
   197
      } else {
marci@301
   198
	//actual_node=G.aNode(dfs_stack.top());
marci@301
   199
	dfs_stack.pop();
marci@301
   200
      }
marci@301
   201
      return *this;
marci@301
   202
    }
marci@301
   203
    bool finished() const { return dfs_stack.empty(); }
marci@409
   204
    operator OutEdgeIt() const { return actual_edge; }
marci@301
   205
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@303
   206
    bool isANodeExamined() const { return !(graph->valid(actual_edge)); }
marci@301
   207
    Node aNode() const { return actual_node; /*FIXME*/}
marci@389
   208
    Node bNode() const { return graph->bNode(actual_edge); }
marci@301
   209
    const ReachedMap& getReachedMap() const { return reached; }
marci@301
   210
    const std::stack<OutEdgeIt>& getDfsStack() const { return dfs_stack; }
marci@301
   211
  };
marci@301
   212
marci@448
   213
  /// Dfs searches from s for the nodes wich are not marked in 
marci@448
   214
  /// \c reached_map
marci@448
   215
  /// Reached is a read-write bool-map, Pred is a write-nodemap, have to be.
marci@448
   216
  template <typename Graph, 
marci@448
   217
	    typename ReachedMap=typename Graph::template NodeMap<bool>, 
marci@448
   218
	    typename PredMap
marci@448
   219
	    =typename Graph::template NodeMap<typename Graph::Edge> > 
marci@448
   220
  class Dfs : public DfsIterator<Graph, ReachedMap> {
marci@448
   221
    typedef DfsIterator<Graph, ReachedMap> Parent;
marci@448
   222
  protected:
marci@448
   223
    typedef typename Parent::Node Node;
marci@448
   224
    PredMap& pred;
marci@448
   225
  public:
marci@448
   226
    Dfs<Graph, ReachedMap, PredMap>(const Graph& _graph, ReachedMap& _reached, PredMap& _pred) : DfsIterator<Graph, ReachedMap>(_graph, _reached), pred(&_pred) { }
marci@448
   227
    /// s is marked to be reached and pushed in the bfs queue.
marci@448
   228
    /// If the queue is empty, then the first out-edge is processed.
marci@448
   229
    /// If s was not marked previously, then 
marci@448
   230
    /// in addition its pred is set to be INVALID. 
marci@448
   231
    /// if s was marked previuosly, then it is simply pushed.
marci@448
   232
    void push(Node s) { 
marci@448
   233
      if (this->reached[s]) {
marci@448
   234
	Parent::pushAndSetReached(s);
marci@448
   235
      } else {
marci@448
   236
	Parent::pushAndSetReached(s);
marci@448
   237
	pred.set(s, INVALID);
marci@448
   238
      }
marci@448
   239
    }
marci@448
   240
    /// A bfs is processed from s.
marci@448
   241
    void run(Node s) {
marci@448
   242
      push(s);
marci@448
   243
      while (!this->finished()) this->operator++();
marci@448
   244
    }
marci@448
   245
    Dfs<Graph, ReachedMap, PredMap> operator++() {
marci@448
   246
      Parent::operator++();
marci@448
   247
      if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) 
marci@448
   248
      {
marci@448
   249
	pred.set(this->bNode(), this->actual_edge);
marci@448
   250
      }
marci@448
   251
      return *this;
marci@448
   252
    }
marci@448
   253
    const PredMap& getPredMap() const { return pred; }
marci@448
   254
  };
marci@448
   255
marci@448
   256
marci@301
   257
} // namespace hugo
marci@301
   258
marci@301
   259
#endif //HUGO_BFS_ITERATOR_H