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