#ifndef GRAFO_H_
#define GRAFO_H_
#include <list>
#include <iostream>
#define INFINITO 9999999;
//-----------------------------------------------------------------------------------------------//
using namespace std;
//-------------------------------------- CLASE GRAFO ------------------------------------------//
template <typename C> class Grafo
{
public:
//-------------------------------------- CLASE GRAFO ------------------------------------------//
class Arco
{
public:
Arco();
Arco(const Arco & otroArco);
Arco(int adyacente, const C & costo);
int devolverAdyacente() const;
const C & devolverCosto() const;
int vertice;
C costo;
};
public:
Grafo();
Grafo(const Grafo & otroGrafo);
~Grafo();
Grafo & operator = (const Grafo & otroGrafo);
bool estaVacio() const; // Devuelve true si la cantidad de vértices es cero
int devolverLongitud() const; // Indica la cantidad de vértices del grafo
bool existeVertice(int vertice) const;
bool existeArco(int origen, int destino) const;
const C & costoArco(int origen, int destino) const; // PRE CONDICION: existeArco(origen, destino)
void devolverVertices(list<int> & vertices) const;
void devolverAdyacentes(int origen, list<Arco> & adyacentes) const;
void agregarVertice(int vertice);
void eliminarVertice(int vertice); // POST CONDICION: Para todo vértice v != vertice: !existeArco(v, vertice) && !existeArco(vertice, v)
void agregarArco(int origen, int destino, const C & costo); // PRE CONDICION: existeVertice(origen) && existeVertice(destino) // POST CONDICION: existeArco(origen, destino)
void eliminarArco(int origen, int destino); // POST CONDICION: !existeArco(origen, destino)
void vaciar();
private:
struct NGrafo{
int vertice;
list<Arco> adyacentes;
};
list<NGrafo> grafo;
};
//-----------------------------------------------------------------------------------------------//
//------------------------------- Implementacion clase ARCO -------------------------------------//
//-----------------------------------------------------------------------------------------------//
template <typename C> Grafo<C>::Arco::Arco()
{
}
//-----------------------------------------------------------------------------------------------//
template <typename C> Grafo<C>::Arco::Arco(const Arco & otroArco)
{
this->costo = otroArco.devolverCosto();
this->vertice = otroArco.devolverAdyacente();
}
//-----------------------------------------------------------------------------------------------//
template <typename C> Grafo<C>::Arco::Arco(int adyacente, const C & costo)
{
vertice = adyacente;
this->costo = costo;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> int Grafo<C>::Arco::devolverAdyacente() const
{
return this->vertice;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> const C & Grafo<C>::Arco::devolverCosto() const
{
return costo;
}
//-----------------------------------------------------------------------------------------------//
//------------------------------- Implementacion clase GRAFO ------------------------------------//
//-----------------------------------------------------------------------------------------------//
template <typename C> ostream & operator << (ostream & salida, const Grafo<C> & grafo)
{
list<int> vertices; //Recorremos todos los vertices
grafo.devolverVertices(vertices);
list<int>::iterator v;
v = vertices.begin();
cout << endl << "//------------------------------- GRAFO ------------------------------------//" << endl << endl;
while (v != vertices.end())
{
salida << "Vertice: " << *v << endl; // Recorremos todos los adyacentes de cada vertice
list<typename Grafo<C>::Arco> adyacentes;
grafo.devolverAdyacentes(*v, adyacentes);
typename list<typename Grafo<C>::Arco>::iterator ady;
ady = adyacentes.begin();
while (ady != adyacentes.end())
{
salida << " " << "-> " << ady->devolverAdyacente() << " con costo: (" << ady->costo << ")" << endl;
ady++;
}
v++;
cout << endl;
}
cout << "//-------------------------------------------------------------------------//" << endl << endl;
return salida;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> Grafo<C>::Grafo()
{
}
//-----------------------------------------------------------------------------------------------//
template <typename C> Grafo<C>::Grafo(const Grafo & otroGrafo)
{
list<int> otroGrafo_vertices;
list<Arco> otroGrafo_adyacentes;
vaciar();
typename list<int>::const_iterator vertices;
otroGrafo.devolverVertices(otroGrafo_vertices);
for(vertices = otroGrafo_vertices.begin(); vertices != otroGrafo_vertices.end(); vertices++)
this->agregarVertice(*vertices);
typename list<int>::const_iterator otroGrafo_iterador;
typename list<Arco>::const_iterator otroGrafo_adyacentes_iterador;
for(vertices = otroGrafo_vertices.begin(); vertices != otroGrafo_vertices.end(); vertices++, otroGrafo_adyacentes_iterador++)
{
otroGrafo.devolverAdyacentes(*vertices,otroGrafo_adyacentes);
for(otroGrafo_adyacentes_iterador = otroGrafo_adyacentes.begin(); otroGrafo_adyacentes_iterador != otroGrafo_adyacentes.end(); otroGrafo_adyacentes_iterador++)
agregarArco(*vertices, otroGrafo_adyacentes_iterador->devolverAdyacente(), otroGrafo_adyacentes_iterador->devolverCosto());
}
}
//-----------------------------------------------------------------------------------------------//
template <typename C> Grafo<C>::~Grafo()
{
}
//-----------------------------------------------------------------------------------------------//
template <typename C> Grafo<C> & Grafo<C>::operator = (const Grafo & otroGrafo)
{
list<int> otroGrafo_vertices;
list<Arco> otroGrafo_adyacentes;
vaciar();
typename list<int>::const_iterator vertices;
otroGrafo.devolverVertices(otroGrafo_vertices);
for(vertices = otroGrafo_vertices.begin(); vertices != otroGrafo_vertices.end(); vertices++)
this->agregarVertice(*vertices);
typename list<int>::const_iterator otroGrafo_iterador;
typename list<Arco>::const_iterator otroGrafo_adyacentes_iterador;
for(vertices = otroGrafo_vertices.begin(); vertices != otroGrafo_vertices.end(); vertices++, otroGrafo_adyacentes_iterador++)
{
otroGrafo.devolverAdyacentes(*vertices,otroGrafo_adyacentes);
for(otroGrafo_adyacentes_iterador = otroGrafo_adyacentes.begin(); otroGrafo_adyacentes_iterador != otroGrafo_adyacentes.end(); otroGrafo_adyacentes_iterador++)
agregarArco(*vertices, otroGrafo_adyacentes_iterador->devolverAdyacente(), otroGrafo_adyacentes_iterador->devolverCosto());
}
}
//-----------------------------------------------------------------------------------------------//
template <typename C> bool Grafo<C>::estaVacio() const
{
return grafo.size();
}
//-----------------------------------------------------------------------------------------------//
template <typename C> int Grafo<C>::devolverLongitud() const
{
return grafo.size();
}
//-----------------------------------------------------------------------------------------------//
template <typename C> bool Grafo<C>::existeVertice(int vertice) const
{
typename list<NGrafo>::const_iterator it;
it = grafo.begin();
while ((it != grafo.end())&&(it->vertice != vertice))
it++;
if (it != grafo.end())
return true;
else
return false;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> bool Grafo<C>::existeArco(int origen, int destino) const
{
list<Arco> adyacentes;
devolverAdyacentes(origen,adyacentes);
if(adyacentes.size())
{
typename list<Arco>::const_iterator it;
it = adyacentes.begin();
while((it != adyacentes.end())&&(it->devolverAdyacente() != destino))
it++;
if (it != adyacentes.end())
return true;
else
return false;
}
else
return false;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> const C & Grafo<C>::costoArco(int origen, int destino) const
{
list<Arco> adyacentes;
devolverAdyacentes(origen,adyacentes);
if (adyacentes.size())
{
typename list<Arco>::const_iterator it;
it = adyacentes.begin();
while ((it != adyacentes.end())&&(it->devolverAdyacente() != destino))
it++;
if (it != adyacentes.end())
return it->devolverCosto();
}
return INFINITO;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> void Grafo<C>::devolverVertices(list<int> & vertices) const
{
typename list<NGrafo>::const_iterator it;
it = grafo.begin();
while (it != grafo.end())
{
vertices.push_back(it->vertice);
it++;
}
}
//-----------------------------------------------------------------------------------------------//
template <typename C> void Grafo<C>::devolverAdyacentes(int origen, list<Arco> & adyacentes) const
{
if(existeVertice(origen))
{
typename list<NGrafo>::const_iterator it;
it = grafo.begin();
while ((it != grafo.end())&&(it->vertice != origen))
it++;
adyacentes = it->adyacentes;
}
}
//-----------------------------------------------------------------------------------------------//
template <typename C> void Grafo<C>::agregarVertice(int vertice)
{
NGrafo Nuevo;
Nuevo.vertice = vertice;
this->grafo.push_back(Nuevo);
}
//-----------------------------------------------------------------------------------------------//
template <typename C> void Grafo<C>::eliminarVertice(int vertice)
{
typename list<NGrafo>::iterator it;
it = grafo.begin();
while((it != grafo.end())&&(it->vertice != vertice))
it++;
if(it != grafo.end())
{
it->adyacentes.clear();
grafo.erase(it);
}
else
cout << "El elemento que desea borrar no existe" << endl;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> void Grafo<C>::agregarArco(int origen, int destino, const C & costo)
{
// para hacer esta funcion, se verifica de que existan los vertices, si existen se busca la lista de adyacentes y se verifica de que no exista el arco.
typename list<NGrafo>::iterator begin;
typename list<NGrafo>::iterator origen_vertice;
typename list<Arco>::const_iterator it_adyacentes;
typename list<Arco>::const_iterator it_adyacentes_end;
begin = grafo.begin();
bool _origen = false;
bool _destino = false; // se comienza con los dos vertices no encontrados (false)
while ((begin != grafo.end())&&((!_origen)||(!_destino)))
{
if ((begin->vertice == origen)&&(!_origen))
{
_origen = true;
it_adyacentes = begin->adyacentes.begin();
origen_vertice = begin;
it_adyacentes_end = begin->adyacentes.end();
}
if ((begin->vertice == destino)&&(!_destino))
_destino = true;
begin++;
}
if ((_origen)&&(_destino))
{
while ((it_adyacentes != it_adyacentes_end)&&(it_adyacentes->devolverAdyacente() != destino))
it_adyacentes++;
if (it_adyacentes == it_adyacentes_end)
{
Arco nuevo(destino,costo);
origen_vertice->adyacentes.push_back(nuevo);
}
}
else
cout << "No es posible agregar el arco, uno o mas vertices no existen" << endl;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> void Grafo<C>::eliminarArco(int origen, int destino)
{
typename list<NGrafo>::iterator begin;
typename list<NGrafo>::iterator origen_vertice;
typename list<Arco>::iterator it_adyacentes;
typename list<Arco>::const_iterator it_adyacentes_end;
begin = grafo.begin();
bool _origen = false;
bool _destino = false; // se comienza con los dos vertices no encontrados (false)
while ((begin != grafo.end())&&((!_origen)||(!_destino)))
{
if ((begin->vertice == origen)&&(!_origen))
{
_origen = true;
it_adyacentes = begin->adyacentes.begin();
origen_vertice = begin;
it_adyacentes_end = begin->adyacentes.end();
}
if ((begin->vertice == destino)&&(!_destino))
_destino = true;
begin++;
}
if ((_origen)&&(_destino))
{
while ((it_adyacentes != it_adyacentes_end)&&(it_adyacentes->devolverAdyacente() != destino))
it_adyacentes++;
if (it_adyacentes != it_adyacentes_end)
origen_vertice->adyacentes.erase(it_adyacentes);
else
cout << "No es posible eliminar el arco, uno o mas vertices no existen" << endl;
}
else
cout << "No es posible eliminar el arco, uno o mas vertices no existen" << endl;
}
//-----------------------------------------------------------------------------------------------//
template <typename C> void Grafo<C>::vaciar()
{
typename list<NGrafo>::iterator it;
typename list<Arco>::iterator borrar;
typename list<Arco>::iterator borrar_aux;
it = grafo.begin();
while(it!=grafo.end())
{
borrar = it->adyacentes.begin();
while(borrar != it->adyacentes.end())
{
borrar_aux = borrar;
borrar++;
it->adyacentes.erase(borrar_aux);
}
it++;
}
grafo.clear();
}
//-----------------------------------------------------------------------------------------------//
#endif /* GRAFO_H_ */