Si todo arco puede ser recorrido en ambos sentidos, el grafo es no dirigido. Para el caso de grafos dirigidos, cada arco tiene una dirección, generalmente representado por su nodo origen y su nodo destino.
Los grafos son una forma de representación de un conjunto de nodos (o vértices) unidos entre sí por unas líneas denominadas arcos (o aristas).
Usos
Veamos algunos ejemplos donde la estructura de datos grafos puede ser muy util :
Análisis de circuitos eléctricos.
Determinación del camino más corto.
Análisis de planificación de proyectos.
Identificación de compuestos químicos.
Entre muchos más, ya que grafos es la estructura matemática más usada.
Clasificación de grafos
Los grafos se pueden clasificar en dos grupos:
a-Dirigidos
Los grafos son una forma de representación de un conjunto de nodos (o vértices) unidos entre sí por unas líneas denominadas arcos (o aristas).
Usos
Veamos algunos ejemplos donde la estructura de datos grafos puede ser muy util :
Análisis de circuitos eléctricos.
Determinación del camino más corto.
Análisis de planificación de proyectos.
Identificación de compuestos químicos.
Entre muchos más, ya que grafos es la estructura matemática más usada.
Clasificación de grafos
Los grafos se pueden clasificar en dos grupos:
a-Dirigidos
b-No dirigidos.
un grafo no dirigido el par de vértices que representa un arco no está ordenado. Por lo tanto, los pares (v1, v2) y (v2, v1) representan el mismo arco.
en un grafo dirigido cada arco está representado por un par ordenado de vértices, de forma que y representan dos arcos diferentes.
Ejemplos
G1 = (V1, A1)
V1 = {1, 2, 3, 4} A1 = {(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)}
G2 = (V2, A2)
V2 = {1, 2, 3, 4, 5, 6} A2 = {(1, 2), (1, 3), (2, 4), (2, 5), (3, 6)}
G3 = (V3, A3)
V3 = {1, 2, 3} A3 = { <1,>, <2,>, <2,> }
Gráficamente estas tres estructuras de vértices y arcos se pueden representar de la siguiente manera:
Algunos de los principales tipos de grafos son los que se muestran a continuación:
· Grafo regular: Aquel con el mismo grado en todos los vértices. Si ese grado es k lo llamaremos k-regular.
Ejemplos
G1 = (V1, A1)
V1 = {1, 2, 3, 4} A1 = {(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)}
G2 = (V2, A2)
V2 = {1, 2, 3, 4, 5, 6} A2 = {(1, 2), (1, 3), (2, 4), (2, 5), (3, 6)}
G3 = (V3, A3)
V3 = {1, 2, 3} A3 = { <1,>, <2,>, <2,> }
Gráficamente estas tres estructuras de vértices y arcos se pueden representar de la siguiente manera:
Algunos de los principales tipos de grafos son los que se muestran a continuación:
· Grafo regular: Aquel con el mismo grado en todos los vértices. Si ese grado es k lo llamaremos k-regular.

· Grafo bipartito:
Es aquel con cuyos vértices pueden formarse dos conjuntos disjuntos de modo que no haya adyacencias entre vértices pertenecientes al mismo conjunto.
Ejemplo.
Ejemplo.

· Grafo completo: Aquel con una arista entre cada ar de vértices. Un grafo completo con n vértices se denota Kn.
· Un grafo bipartito regular: se denota Km,n donde m, n es el grado de cada conjunto disjunto de vértices.
· Grafo nulo: Se dice que un grafo es nulo cuando los vértices que lo componen no están conectados, esto es, que son vértices aislados. ·

Grafos Isomorfos: Dos grafos son isomorfos cuando existe una correspondencia biunívoca (uno a uno), entre sus vértices de tal forma que dos de estos quedan unidos por una arista en común.

Grafos Platónicos: Son los Grafos formados por los vértices y aristas de los cinco sólidos regulares (Sólidos Platónicos), a saber, el tetraedro, el cubo, el octaedro, el dodecaedro y el icosaedro.

Grafos Eulerianos.
Para definir un camino euleriano es importante definir un camino euleriano primero. Un camino euleriano se define de la manera más sencilla como un camino que contiene todos los arcos del grafo.
Teniendo esto definido podemos hablar de los grafos eulerianos describiéndolos simplemente como aquel grafo que contiene un camino euleriano. Como ejemplos tenemos la siguiente imágen:

El primer grafo de ellos no contiene caminos eulerianos mientras el segundo contiene al menos uno.
Grafos Conexos.
Un grafo se puede definir como conexo si cualquier vértice V pertenece al conjunto de vértices y es alcanzable por algún otro. Otra definición que dejaría esto más claro sería: "un grafo conexo es un grafo no dirigido de modo que para cualquier par de nodos existe al menos un camino que los une".
Recorridos de Grafos
En muchas aplicaciones es necesario visitar todos los vértices del grafo a partir de un nodo dado. Algunas aplicaciones son:
Encontrar ciclos
Encontrar componentes conexas
Encontrar árboles cobertores
Hay dos enfoque básicos:
Recorrido (o búsqueda) en profundidad (depth-first search): La idea es alejarse lo más posible del nodo inicial (sin repetir nodos), luego devolverse un paso e intentar lo mismo por otro camino.
Recorrido (o búsqueda) en amplitud (breadth-first search): Se visita a todos los vecinos directos del nodo inicial, luego a los vecinos de los vecinos, etc.
Recorrido en Profundidad (DFS)
A medida que recorremos el grafo, iremos numerando correlativamente los nodos encontrados (1,2,...). Suponemos que todos estos números son cero inicialmente, y utilizamos un contador global n, también inicializado en cero.
El siguiente algoritmo en seudo-código muestra cómo se puede hacer este tipo de recorrido recursivamente:
DFS(v) // recorre en profundidad a partir del vértice v
{
++n;
DFN[v]=n;
for(todo w tal que {v,w} está en E y DFN[w]==0)
DFS(w);
}
Para hacer un recorrido en profundidad a partir del nodo v, utilizamos el siguiente programa principal:
n=0;
for(todo w)
DFN[w]=0;
DFS(v);
Si hubiera más de una componente conexa, esto no llegaría a todos los nodos. Para esto podemos hacer:
n=0;
ncc=0; // número de componentes conexas
for(todo w)
DFN[w]=0;
while(existe v en V con DFN[v]==0)
{
++ncc;
DFS(v);
}
Ejercicio: ¿Cómo utilizar este algoritmo para detectar si un grafo es acíclico?
También es posible implementar un recorrido no recursivo utilizando una pila:
Pila pila=new Pila();
n=0;
for(todo w)
DFN[w]=0;
pila.apilar(v); // para recorrer a partir de v
while(!pila.estaVacia())
{
v=pila.desapilar();
if(DFN[v]==0) // primera vez que se visita este nodo
{
++n;
DFN[v]=n;
for(todo w tal que {v,w} esta en E)
pila.apilar(w);
}
}
Bibliografia:
En muchas aplicaciones es necesario visitar todos los vértices del grafo a partir de un nodo dado. Algunas aplicaciones son:
Encontrar ciclos
Encontrar componentes conexas
Encontrar árboles cobertores
Hay dos enfoque básicos:
Recorrido (o búsqueda) en profundidad (depth-first search): La idea es alejarse lo más posible del nodo inicial (sin repetir nodos), luego devolverse un paso e intentar lo mismo por otro camino.
Recorrido (o búsqueda) en amplitud (breadth-first search): Se visita a todos los vecinos directos del nodo inicial, luego a los vecinos de los vecinos, etc.
Recorrido en Profundidad (DFS)
A medida que recorremos el grafo, iremos numerando correlativamente los nodos encontrados (1,2,...). Suponemos que todos estos números son cero inicialmente, y utilizamos un contador global n, también inicializado en cero.
El siguiente algoritmo en seudo-código muestra cómo se puede hacer este tipo de recorrido recursivamente:
DFS(v) // recorre en profundidad a partir del vértice v
{
++n;
DFN[v]=n;
for(todo w tal que {v,w} está en E y DFN[w]==0)
DFS(w);
}
Para hacer un recorrido en profundidad a partir del nodo v, utilizamos el siguiente programa principal:
n=0;
for(todo w)
DFN[w]=0;
DFS(v);
Si hubiera más de una componente conexa, esto no llegaría a todos los nodos. Para esto podemos hacer:
n=0;
ncc=0; // número de componentes conexas
for(todo w)
DFN[w]=0;
while(existe v en V con DFN[v]==0)
{
++ncc;
DFS(v);
}
Ejercicio: ¿Cómo utilizar este algoritmo para detectar si un grafo es acíclico?
También es posible implementar un recorrido no recursivo utilizando una pila:
Pila pila=new Pila();
n=0;
for(todo w)
DFN[w]=0;
pila.apilar(v); // para recorrer a partir de v
while(!pila.estaVacia())
{
v=pila.desapilar();
if(DFN[v]==0) // primera vez que se visita este nodo
{
++n;
DFN[v]=n;
for(todo w tal que {v,w} esta en E)
pila.apilar(w);
}
}
Bibliografia:
No hay comentarios:
Publicar un comentario