00001 /* ADH_Graph.cpp (C) 2007 [email protected] */ 00002 00003 #include "ADH_Graph.h" 00004 00005 /** \file ADH_Graph.cpp 00006 \brief Archivo de implementaci¢n para \c ADH_Graph.h 00007 00008 \author Adolfo Di Mare <[email protected]> 00009 \date 2007 00010 */ 00011 00012 00013 namespace ADH { 00014 00015 /** Verifica la invariante del grafo. 00016 - Regresa \c "true" si el grafo \c "DDD" contiene un valor correcto 00017 - Podría retornar \c "true" para un grafo lista cuyo valor está corrupto 00018 - Podría no retornar si el grafo tiene su valor corrupto 00019 00020 - Como los valores del grafo están ordenados, verifica 00021 que la lista que DDD contiene esté ordenada 00022 00023 \par Rep Diagrama de la clase 00024 \code 00025 m_DICC[] 00026 +------+-----------------------------------+ 00027 | | +---------+---------+-----------+ | 00028 | F | | A(1)=>2 | A(2)=>8 | A(3)==>64 | | 00029 | | +---------+---------+-----------+ | 00030 +------+-----------------------------------+ 00031 | | +------+ | A(1) C(1) 00032 | A(1) | | B=>2 | | / \ / \ 00033 | | +------+ | / \ / \ 00034 +------+-----------------------------------+ F----A(2)----B-- --D 00035 | | +------+ | \ / \ / 00036 | A(2) | | B=>8 | | \ / \ / 00037 | | +------+ | A(3) C(2) 00038 +------+-----------------------------------+ 00039 | | +-------+ | 00040 | A(3) | | B=>64 | | G.set("F", "A(1)", 2 ); G.set( "A(1)", "B", 2 ); 00041 | | +-------+ | G.set("F", "A(2)", 8 ); G.set( "A(2)", "B", 8 ); 00042 +------+-----------------------------------+ G.set("F", "A(3)", 64 ); G.set( "A(3)", "B", 64 ); 00043 | | +---------+----------+ | 00044 | B | | C(1)=>3 | C(2)=>27 | | G.set("B", "C(1)", 3 ); G.set( "C(1)", "D", 3 ); 00045 | | +---------+----------+ | G.set("B", "C(2)", 27 ); G.set( "C(2)", "D", 27 ); 00046 +------+-----------------------------------+ 00047 | | +------+ | 00048 | C(1) | | D=>2 | | 00049 | | +------+ | 00050 +------+-----------------------------------+ 00051 | | +------+ | 00052 | C(2) | | D=>8 | | 00053 | | +------+ | 00054 +------+-----------------------------------+ 00055 | | +-+ | 00056 | D | | | | D no es salida de ninguna arista 00057 | | +-+ | - Su diccionario está vacío 00058 +------+-----------------------------------+ 00059 \endcode 00060 00061 - El grafo está implementado como un diccionario que contiene otro diccionario. 00062 - La llave del diccionario principal es el vértice que comienza un arco. 00063 - Cada vértice tiene asociado un diccionario cuya llave es el vértice de destino. 00064 Este es el diccionario que representa cada arista. 00065 - El valor numérico asociado en el diccionario de cada arista es el valor de la arista. 00066 - Si un vértice no participa en ninguna arista, tampoco aparece en el grafo. 00067 /// - En el grado sólo están almacenados los vértices que participan en alguna arista. 00068 */ 00069 bool check_ok( const Graph & DDD ) { 00070 if ( & DDD == 0 ) { 00071 /// - Invariante: ningún objeto puede estar almacenado en la posición nula. 00072 return false; 00073 } 00074 return true; 00075 } 00076 00077 /// Establece que el grafo tiene la arista \c src->dst con valor \c "val". 00078 /// - Si ya la arista estaba en el grafo, no la agrega ni le cambia el valor asociado. 00079 void Graph::set( const std::string & src , const std::string & dst , int val ) { 00080 { // Agrega primero los 2 vértices del arco (si no han sido agregados antes) 00081 m_DICC.insert( make_pair( src, Rep::mapped_type() ) ); 00082 m_DICC.insert( make_pair( dst, Rep::mapped_type() ) ); // lo agrega si no estaba 00083 } 00084 { Rep::iterator it = m_DICC.find( src ); 00085 // Ya existe ese vértice en el diccionario 00086 it->second.insert( make_pair( dst , val ) ); 00087 } 00088 return; 00089 00090 /* Nota: 00091 No es posible implementar esta operación usando 2 iteradores para recorrer 00092 "m_DICC". Si uno lo hace, el programa explota en tiempo de ejecución. 00093 - Los iteradores del diccionario std::map<> no se pueden copiar, pues no 00094 tienen su "operator=()" definido. 00095 - Un diccionario sólo puede tener un iterador que no sea "const", que es el 00096 único que puede cambiarlo. Los otros iteradores deben ser "const". 00097 - Así se evita que, al usar más de 1 iterador, el diccionario quede modificado 00098 de una forma indeseable. 00099 - Como no existe std::map<>::iterator.operator=(), lo más saludable al usar 00100 un iterador para modificar std::map<> es incluir en bloques { } el código 00101 en donde está definido el iterador, porque la única forma de inicializar 00102 std::map<>::iterator es usando su constructor: 00103 { Rep::iterator it = m_DICC.find( src ); ... } 00104 */ 00105 } 00106 00107 /// Establece que el grafo tiene el vértice \c vtx. 00108 void Graph::set( const std::string & vtx ) { 00109 #if 1 00110 { // Agrega el vértice sin arco (diccionario asociado vacío) 00111 m_DICC.insert( make_pair( vtx, Rep::mapped_type() ) ); 00112 } 00113 #else 00114 Rep::iterator it = m_DICC.find( vtx ); 00115 if ( it == m_DICC.end() ) { 00116 // Agrega el vértice sin aristas. 00117 Rep::mapped_type D; 00118 m_DICC.insert( make_pair( vtx , D ) ); 00119 } 00120 #endif 00121 } 00122 00123 /** Retorna \c "true" si existe el vértice \c vtx. 00124 00125 \dontinclude test_Graph.cpp 00126 \skipline test::isVertex() 00127 \until }} 00128 \see test_Graph::test_isVertex() 00129 */ 00130 bool Graph::isVertex( const std::string & vtx ) const { 00131 Graph::Rep::const_iterator it = m_DICC.find( vtx ); 00132 return ( it != m_DICC.end() ); 00133 } 00134 00135 /** Retorna \c "true" si existe el arco \c src->dst. 00136 - Si el arco existe, en \c val se copia el valor asociado al arco. 00137 - Si el arco no existe, retorna \c "false" y no cambia el valor de \c val. 00138 00139 \dontinclude test_Graph.cpp 00140 \skipline test::isVertex() 00141 \until }} 00142 \see test_Graph::test_isVertex() 00143 */ 00144 bool Graph::isArc( const std::string & src , const std::string & dst , int & val ) const { 00145 Graph::Rep::const_iterator it = m_DICC.find( src ); 00146 if ( it == m_DICC.end() ) { 00147 return false; 00148 } 00149 else { 00150 // Ya existe ese vértice en el diccionario 00151 Graph::mapped_type::const_iterator jt = it->second.find( dst ); 00152 if ( jt == it->second.end() ) { 00153 return false; 00154 } 00155 else { 00156 val = jt->second; 00157 return true; 00158 } 00159 } 00160 } 00161 00162 /// Graba el valor de \c "G" en el flujo \c "COUT". 00163 std::ostream& operator<< (std::ostream &COUT, const Graph& G) { 00164 Graph::Rep::const_iterator it = G.m_DICC.begin(); // recorre m_DICC[] 00165 for ( ; it != G.m_DICC.end(); ++it ) { 00166 COUT << it->first << " ==> ["; 00167 Graph::mapped_type::const_iterator jt = it->second.begin(); 00168 while ( jt != it->second.end() ) { 00169 COUT << '<' << jt->second << '>' << jt->first ; 00170 ++jt; 00171 if ( jt != it->second.end() ) { 00172 COUT << " , "; 00173 } 00174 } 00175 COUT << ']' << std::endl; 00176 } 00177 return COUT; 00178 } // operator << 00179 00180 /// Graba el valor de \c "G" en el flujo \c "COUT". 00181 void dump( std::ostream & COUT, const Graph& G ) { 00182 Graph::Rep::const_iterator it = G.m_DICC.begin(); 00183 for ( ; it != G.m_DICC.end(); ++it ) { 00184 Graph::Rep::const_iterator jt = G.m_DICC.begin(); 00185 for ( ; jt != G.m_DICC.end(); ++jt ) { 00186 int val = 666; 00187 if ( G.isArc( it->first , jt->first , val ) ) { 00188 COUT << it->first << "->" << jt->first << " == " << val << std::endl; 00189 } 00190 } 00191 } 00192 } 00193 00194 /** Determina si existe un camino en el grafo comenzando en \c "src" y terminando en \c "dst". 00195 - Retorna \c "true" cuando el camino existe, y \c "false" en caso contrario. 00196 - La lista \c "C" contiene la secuencia de nodos del camino. 00197 - Si no hay camino, la lista \c "C" queda vacía. 00198 00199 \dontinclude test_Graph.cpp 00200 \skipline test::diagram() 00201 \until }} 00202 \skipline test::connected() 00203 \until }} 00204 \see test_Graph::test_connected() 00205 */ 00206 bool Graph::connected( const std::string & src , const std::string & dst , std::list< std::string > & C ) { 00207 int val = 0; 00208 bool res = false; 00209 Graph::Rep::const_iterator it = m_DICC.find( src ); 00210 00211 if ( it == m_DICC.end() ) { 00212 return false; 00213 } 00214 else { 00215 00216 C.push_back(src); 00217 for (int i = 0; i != it->second.size(); ++i ) { 00218 std::map< std::string, int >::const_iterator jt = it->second.begin(); 00219 for ( ; jt != it->second.end(); ++jt ) { 00220 if ( isArc(jt->first, dst, val)){ 00221 C.push_back(jt->first); 00222 C.push_back(dst); 00223 res = true; 00224 return res; 00225 } 00226 else{ 00227 res = connected(jt->first, dst, C); 00228 } 00229 00230 } 00231 00232 //++it 00233 } 00234 00235 } 00236 00237 return res; 00238 } 00239 00240 00241 } // namespace ADH 00242 00243 // EOF: ADH_Graph.cpp
1.4.1