// -*- c++ -*- #ifndef HUGO_BFS_DFS_H #define HUGO_BFS_DFS_H /// \ingroup galgs /// \file /// \brief Bfs and dfs iterators. /// /// This file contains bfs and dfs iterator classes. /// // /// \author Marton Makai #include #include #include #include namespace hugo { /// Bfs searches for the nodes wich are not marked in /// \c reached_map /// Reached have to work as read-write bool Node-map. /// \ingroup galgs template */ > class BfsIterator { protected: typedef typename Graph::Node Node; typedef typename Graph::OutEdgeIt OutEdgeIt; const Graph* graph; std::queue bfs_queue; ReachedMap& reached; bool b_node_newly_reached; OutEdgeIt actual_edge; bool own_reached_map; public: /// In that constructor \c _reached have to be a reference /// for a bool Node-map. The algorithm will search in a bfs order for /// the nodes which are \c false initially BfsIterator(const Graph& _graph, ReachedMap& _reached) : graph(&_graph), reached(_reached), own_reached_map(false) { } /// The same as above, but the map storing the reached nodes /// is constructed dynamically to everywhere false. BfsIterator(const Graph& _graph) : graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), own_reached_map(true) { } /// The map storing the reached nodes have to be destroyed if /// it was constructed dynamically ~BfsIterator() { if (own_reached_map) delete &reached; } /// This method markes \c s reached. /// If the queue is empty, then \c s is pushed in the bfs queue /// and the first out-edge is processed. /// If the queue is not empty, then \c s is simply pushed. void pushAndSetReached(Node s) { reached.set(s, true); if (bfs_queue.empty()) { bfs_queue.push(s); graph->first(actual_edge, s); if (graph->valid(actual_edge)) { Node w=graph->bNode(actual_edge); if (!reached[w]) { bfs_queue.push(w); reached.set(w, true); b_node_newly_reached=true; } else { b_node_newly_reached=false; } } } else { bfs_queue.push(s); } } /// As \c BfsIterator works as an edge-iterator, /// its \c operator++() iterates on the edges in a bfs order. BfsIterator& operator++() { if (graph->valid(actual_edge)) { graph->next(actual_edge); if (graph->valid(actual_edge)) { Node w=graph->bNode(actual_edge); if (!reached[w]) { bfs_queue.push(w); reached.set(w, true); b_node_newly_reached=true; } else { b_node_newly_reached=false; } } } else { bfs_queue.pop(); if (!bfs_queue.empty()) { graph->first(actual_edge, bfs_queue.front()); if (graph->valid(actual_edge)) { Node w=graph->bNode(actual_edge); if (!reached[w]) { bfs_queue.push(w); reached.set(w, true); b_node_newly_reached=true; } else { b_node_newly_reached=false; } } } } return *this; } /// Guess what? bool finished() const { return bfs_queue.empty(); } /// The conversion operator makes for converting the bfs-iterator /// to an \c out-edge-iterator. ///\bug Edge have to be in HUGO 0.2 operator OutEdgeIt() const { return actual_edge; } /// Guess what? bool isBNodeNewlyReached() const { return b_node_newly_reached; } /// Guess what? bool isANodeExamined() const { return !(graph->valid(actual_edge)); } /// Guess what? Node aNode() const { return bfs_queue.front(); } /// Guess what? Node bNode() const { return graph->bNode(actual_edge); } /// Guess what? const ReachedMap& getReachedMap() const { return reached; } /// Guess what? const std::queue& getBfsQueue() const { return bfs_queue; } }; /// Bfs searches for the nodes wich are not marked in /// \c reached_map /// Reached have to work as a read-write bool Node-map, /// Pred is a write Edge Node-map and /// Dist is a read-write Node-map of integral value, have to be. /// \ingroup galgs template , typename PredMap =typename Graph::template NodeMap, typename DistMap=typename Graph::template NodeMap > class Bfs : public BfsIterator { typedef BfsIterator Parent; protected: typedef typename Parent::Node Node; PredMap& pred; DistMap& dist; public: /// The algorithm will search in a bfs order for /// the nodes which are \c false initially. /// The constructor makes no initial changes on the maps. Bfs(const Graph& _graph, ReachedMap& _reached, PredMap& _pred, DistMap& _dist) : BfsIterator(_graph, _reached), pred(&_pred), dist(&_dist) { } /// \c s is marked to be reached and pushed in the bfs queue. /// If the queue is empty, then the first out-edge is processed. /// If \c s was not marked previously, then /// in addition its pred is set to be \c INVALID, and dist to \c 0. /// if \c s was marked previuosly, then it is simply pushed. void push(Node s) { if (this->reached[s]) { Parent::pushAndSetReached(s); } else { Parent::pushAndSetReached(s); pred.set(s, INVALID); dist.set(s, 0); } } /// A bfs is processed from \c s. void run(Node s) { push(s); while (!this->finished()) this->operator++(); } /// Beside the bfs iteration, \c pred and \dist are saved in a /// newly reached node. Bfs& operator++() { Parent::operator++(); if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) { pred.set(this->bNode(), this->actual_edge); dist.set(this->bNode(), dist[this->aNode()]); } return *this; } /// Guess what? const PredMap& getPredMap() const { return pred; } /// Guess what? const DistMap& getDistMap() const { return dist; } }; /// Dfs searches for the nodes wich are not marked in /// \c reached_map /// Reached have to be a read-write bool Node-map. /// \ingroup galgs template */ > class DfsIterator { protected: typedef typename Graph::Node Node; typedef typename Graph::OutEdgeIt OutEdgeIt; const Graph* graph; std::stack dfs_stack; bool b_node_newly_reached; OutEdgeIt actual_edge; Node actual_node; ReachedMap& reached; bool own_reached_map; public: /// In that constructor \c _reached have to be a reference /// for a bool Node-map. The algorithm will search in a dfs order for /// the nodes which are \c false initially DfsIterator(const Graph& _graph, ReachedMap& _reached) : graph(&_graph), reached(_reached), own_reached_map(false) { } /// The same as above, but the map of reached nodes is /// constructed dynamically /// to everywhere false. DfsIterator(const Graph& _graph) : graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), own_reached_map(true) { } ~DfsIterator() { if (own_reached_map) delete &reached; } /// This method markes s reached and first out-edge is processed. void pushAndSetReached(Node s) { actual_node=s; reached.set(s, true); OutEdgeIt e; graph->first(e, s); dfs_stack.push(e); } /// As \c DfsIterator works as an edge-iterator, /// its \c operator++() iterates on the edges in a dfs order. DfsIterator& operator++() { actual_edge=dfs_stack.top(); //actual_node=G.aNode(actual_edge); if (graph->valid(actual_edge)/*.valid()*/) { Node w=graph->bNode(actual_edge); actual_node=w; if (!reached[w]) { OutEdgeIt e; graph->first(e, w); dfs_stack.push(e); reached.set(w, true); b_node_newly_reached=true; } else { actual_node=graph->aNode(actual_edge); graph->next(dfs_stack.top()); b_node_newly_reached=false; } } else { //actual_node=G.aNode(dfs_stack.top()); dfs_stack.pop(); } return *this; } /// Guess what? bool finished() const { return dfs_stack.empty(); } /// Guess what? operator OutEdgeIt() const { return actual_edge; } /// Guess what? bool isBNodeNewlyReached() const { return b_node_newly_reached; } /// Guess what? bool isANodeExamined() const { return !(graph->valid(actual_edge)); } /// Guess what? Node aNode() const { return actual_node; /*FIXME*/} /// Guess what? Node bNode() const { return graph->bNode(actual_edge); } /// Guess what? const ReachedMap& getReachedMap() const { return reached; } /// Guess what? const std::stack& getDfsStack() const { return dfs_stack; } }; /// Dfs searches for the nodes wich are not marked in /// \c reached_map /// Reached is a read-write bool Node-map, /// Pred is a write Node-map, have to be. /// \ingroup galgs template , typename PredMap =typename Graph::template NodeMap > class Dfs : public DfsIterator { typedef DfsIterator Parent; protected: typedef typename Parent::Node Node; PredMap& pred; public: /// The algorithm will search in a dfs order for /// the nodes which are \c false initially. /// The constructor makes no initial changes on the maps. Dfs(const Graph& _graph, ReachedMap& _reached, PredMap& _pred) : DfsIterator(_graph, _reached), pred(&_pred) { } /// \c s is marked to be reached and pushed in the bfs queue. /// If the queue is empty, then the first out-edge is processed. /// If \c s was not marked previously, then /// in addition its pred is set to be \c INVALID. /// if \c s was marked previuosly, then it is simply pushed. void push(Node s) { if (this->reached[s]) { Parent::pushAndSetReached(s); } else { Parent::pushAndSetReached(s); pred.set(s, INVALID); } } /// A bfs is processed from \c s. void run(Node s) { push(s); while (!this->finished()) this->operator++(); } /// Beside the dfs iteration, \c pred is saved in a /// newly reached node. Dfs& operator++() { Parent::operator++(); if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) { pred.set(this->bNode(), this->actual_edge); } return *this; } /// Guess what? const PredMap& getPredMap() const { return pred; } }; } // namespace hugo #endif //HUGO_BFS_DFS_H