Estructura de Datos y Grafos

19
Estructura de Datos y Grafos (Noviembre -2009) Contenido INTRODUCCIÓN .................................................................................................................................. - 1 - CONCEPTOS Y DEFINICIONES............................................................................................................... - 1 - TIPO DE DATO ABSTRACTO GRAFO ...................................................................................................... - 2 - REPRESENTACIÓN DE GRAFOS............................................................................................................. - 2 - MATRIZ DE ADYACENCIA ....................................................................................................................................- 3 - LA CLASE VÉRTICE (VERTEX.CS) ...........................................................................................................................- 4 - IMPLEMENTACIÓN CON MATRIZ DE ADYACENCIA ................................................................................ - 6 - CÓDIGO PARA PROBAR LA IMPLEMENTACIÓN .........................................................................................................- 9 - IMPLEMENTACIÓN CON LISTA DE ADYACENCIA ................................................................................. - 10 - LA CLASE ARCO (ARCH.CS) ...............................................................................................................................- 11 - LA CLASE VÉRTICE (VERTEX.CS) .........................................................................................................................- 11 - LA CLASE GRAFO CON LISTA DE ADYACENCIA (GRAPHLIST.CS) .................................................................................- 14 - CÓDIGO PARA PROBAR LA IMPLEMENTACIÓN .......................................................................................................- 17 - EL MISMO COMPORTAMIENTO ......................................................................................................... - 18 -

Transcript of Estructura de Datos y Grafos

Page 1: Estructura de Datos y Grafos

Estructura de Datos y Grafos

(Noviembre -2009)

Contenido

INTRODUCCIÓN .................................................................................................................................. - 1 -

CONCEPTOS Y DEFINICIONES ............................................................................................................... - 1 -

TIPO DE DATO ABSTRACTO GRAFO ...................................................................................................... - 2 -

REPRESENTACIÓN DE GRAFOS............................................................................................................. - 2 -

MATRIZ DE ADYACENCIA .................................................................................................................................... - 3 -

LA CLASE VÉRTICE (VERTEX.CS) ........................................................................................................................... - 4 -

IMPLEMENTACIÓN CON MATRIZ DE ADYACENCIA ................................................................................ - 6 -

CÓDIGO PARA PROBAR LA IMPLEMENTACIÓN ......................................................................................................... - 9 -

IMPLEMENTACIÓN CON LISTA DE ADYACENCIA ................................................................................. - 10 -

LA CLASE ARCO (ARCH.CS) ...............................................................................................................................- 11 -

LA CLASE VÉRTICE (VERTEX.CS) .........................................................................................................................- 11 -

LA CLASE GRAFO CON LISTA DE ADYACENCIA (GRAPHLIST.CS) .................................................................................- 14 -

CÓDIGO PARA PROBAR LA IMPLEMENTACIÓN .......................................................................................................- 17 -

EL MISMO COMPORTAMIENTO ......................................................................................................... - 18 -

Page 2: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 1 -

Introducción

En esta publicación se pretende introducir al estudiante de Estructura de Datos a un concepto matemático importante, conocido como grafo que tiene aplicaciones en campos diversos como sociología, química, geografía, ingeniería (todas las ramas) y otras disciplinas.

Los grafos se estudian como estructuras de datos o tipos de datos abstractos, en este publicación veremos las formas tradicionales de implementación de grafos, matriz de adyacencia y lista de adyacencia así como operaciones importantes que son significativas desde la informática.

Conceptos y Definiciones

Un grafo reúne elementos y sus relaciones, se trata de la representación más compleja de datos. No existe linealidad ni tampoco jerarquía de manera que no pueden aplicarse tipos de datos abstractos del tipo lista o árbol. Por ello es necesario identificar algunos conceptos y definiciones.

Un grafo está formado por un conjunto de vértices o nodos, que representan a los elementos y un conjunto de arcos que representan las relaciones entre vértices. El grafo se representa con el par G = (V, A), donde V es el conjunto de vértices y A el conjunto de arcos.

V = {1,4,5,7,9}

A = {(1,4), (4,1), (1,5), (5,1), (5,7), (7,5), (7,9), (9,7), (9,4)), (4,9)}

Un arco o arista representa una relación entre dos nodos o vértices. Esta relación, al estar formado por dos nodos se representa por (u, v) siendo u, v el par de nodos. El grafo es no dirigido si los arcos están formados por pares de nodos no ordenados; se representa con un segmento uniendo los nodos u - v.

Un grafo es dirigido, también conocido como digrafo, si los pares de nodos que forman los arcos son ordenados; se representan con una flecha que indica la dirección de la relación, u -> v.

V = {C,D,E,F,H }

A = {(C,D), (D,F), (E,H), (H,E), (E,C)}

Dado el arco (u, v) de un grafo, se dice que los vértices u y v son adyacentes. Si el grafo es dirigido, el vértice "u es adyacente a v", y "v es adyacente de u".

Page 3: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 2 -

En los modelos realizados con grafos, a veces, una relación entre dos nodos tiene asociada información, denominada factor de peso, en cuyo caso se dice que es un grafo valorado o grafo con peso.

El grado es una característica que se refiere a los nodos de un grafo. En un grafo no dirigido, el grado de un nodo es el número de arcos que contienen al nodo. En un grafo dirigido se distingue entre grado de entrada y grado de salida; grado de entrada de un nodo es el número de arcos que llegan (entran) al nodo y grado de salida es el número de arcos que salen del nodo.

Un camino (path) P de longitud n desde el vértice v0 a vn en un grafo G, es la secuencia de n+1 vértices v0, v1, v2, ..., vn tal que (vi, vi+1) Є A (arcos) para 0 ≤ i ≤ n.

En algunos grafos se encuentran arcos desde un vértice a sí mismo, (v, v); entonces, el camino v -> v es un bucle.

Un camino P = {v0, v1, v2, ..., vn} es simple si todos los nodos que forman el camino son distintos, pudiendo ser iguales v0 y vn (los extremos del camino).

En un grafo dirigido, un ciclo es un camino simple cerrado. Por tanto, un ciclo empieza y termina en el mismo nodo, v0 = vn y además debe tener más de un arco. Un grafo dirigido sin ciclos se conoce como Grafo Dirigido Acíclico.

Un grafo no dirigido es conexo si existe un camino entre cualquier par de nodos que forman el grafo. Un grafo dirigido, que tiene un camino entre cualquier par de nodos que forman el grafo se conoce como grafo fuertemente conexo.

Tipo de Dato Abstracto Grafo

Además de representar la información de los vértices o nodos y sus relaciones mediante los arcos o aristas, la definición de tipo de dato abstracto grafo debe indicar las operaciones que pueden realizarse. Entre ellas, las que se consideran básicas, podemos contar con : agregar un vértice, remover un vértice, agregar un arco, remover un arco, determinar si dos vértices son adyacentes.

Por otro lado, cada problema del mundo real que deba representarse utilizando tipos de dato abstractos grafo necesitará de operaciones propias del problema.

Por ejemplo; una empresa que realiza viajes aéreos entre distintos lugares del mundo, puede utilizar los vértices para representar los aeropuertos y los arcos para representar los vuelos entre aeropuertos; de manera que "agregar un vértice" se convierte en "agregar un aeropuerto" y "agregar un arco" se convierte en "agregar un vuelo", sin embargo la operación de agregar un vuelo también debe indicar los días y horarios en que se realiza, esto es información del arco que en la representación básica de un grafo puede no estar considerada.

Por suerte, al utilizar programación orientada a objetos es posible desarrollar una subclase de la clase grafo e incorporar la información de los vuelos, así como un método que muestre las distintas posibilidades para viajar desde un lugar a otro.

Representación de grafos

A la hora de implementar o representar el tipo de dato abstracto grafo, nos encontramos con que es necesario representar en memoria la colección de vértices y la colección de arcos; la primera colección, para los vértices no parece tener inconveniente dado que bastará con un arreglo o una

Page 4: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 3 -

lista, donde se almacenen los vértices, en cambio la segunda colección es un poco más complicada dado que la relación entre vértices es justamente la esencia de los grafos.

Una primera aproximación a la representación de grafos es utilizar un arreglo para representar los vértices y una matriz (arreglo de dos dimensiones) para indicar las relaciones entre vértices.

Matriz de adyacencia

La característica más importante de un grafo, es el conjunto de pares de vértices que están relacionados, en otras palabras que son adyacentes. La forma más simple de representar esta relación es con una matriz, de tantas filas y columnas como vértices tiene el grafo (una matriz cuadrada); en cada intersección de fila - columna se puede tener un valor numérico uno (1) si hay un arco entre el nodo de la fila con el nodo de la columna o cero (0) si no existe dicho arco; por supuesto también se puede realizar con valores booleanos.

Matriz de adyacencia

D F K L R

D 0 1 1 0 0

F 1 0 1 0 0

K 0 1 0 0 0

L 0 1 1 0 0

R 1 0 0 0 0

La realización de esta estructura de datos, la matriz de adyacencia es realmente simple:

/// <summary>

/// Mantiene la matriz de adyacencia del grafo

/// </summary>

private int[,] _AdyacencyMatrix;

/// <summary>

/// Accede a la matriz de adyacencia del grafo

/// </summary>

protected virtual int[,] AdyacencyMatrix

{

get { return _AdyacencyMatrix; }

set { _AdyacencyMatrix = value; }

}

Sin embargo, se observa que en esta representación, las filas y las columnas de la matriz de adyacencia se identifican con los "nombres" de los vértices. Por otro lado es importante destacar que la matriz de adyacencia puede cambiar el orden de las filas y columnas y eso no tiene impacto en la representación de las relaciones (adyacencias), pues quedarán los valores numéricos unos (1) y ceros (0) en otros lugares pero seguirán indicando que existe o no existe un arco entre los vértices indicados por la fila y la columna.

Page 5: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 4 -

La clase vértice (Vertex.cs)

Desde la programación, para manipular la matriz de adyacencia hacen falta los subíndices que indican las filas y columnas, pero los humanos necesitan manipular los vértices por su nombre, de manera que la estructura de datos que representa a los vértices debe mantener ambas cosas.

using System;

namespace DemoGrafo1

{

public class Vertex

{

#region Estructura Interna y Propiedades

/// <summary>

/// Mantiene el nombre del vértice

/// </summary>

private String _Name;

/// <summary>

/// Accede al nombre del vértice

/// </summary>

public virtual String Name

{

get { return _Name; }

set { _Name = value; }

}

/// <summary>

/// Mantiene el número del vértice

/// </summary>

private int _Number;

/// <summary>

/// Accede al número del vertice

/// </summary>

public virtual int Number

{

get { return _Number; }

set { _Number = value; }

}

#endregion

#region Constructores

/// <summary>

/// Constructor por defecto

/// </summary>

public Vertex()

{

Name = String.Empty;

Number = -1;

}

/// <summary>

/// Constructor especializado

/// </summary>

/// <param name="name">Nombre del vértice</param>

public Vertex(String name)

: this()

{

Name = name;

Page 6: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 5 -

}

/// <summary>

/// Constructor especializado

/// </summary>

/// <param name="name">Nombre del vértice</param>

/// <param name="number">Número del vértice</param>

public Vertex(String name, int number)

: this()

{

Name = name;

Number = number;

}

#endregion

#region Heredado de object

/// <summary>

/// Determina si un vértice es igual a otro

/// </summary>

/// <param name="obj">Objeto a comparar</param>

/// <returns>Verdadero si son iguales</returns>

public override bool Equals(object obj)

{

if ((obj != null) && (obj is Vertex))

{

return Equals((Vertex)obj);

}

throw new Exception(String.Format("No se puede comparar con obj =

{0}", (obj == null ? "null" : obj.GetType().ToString())));

}

/// <summary>

/// Determina si dos vértices son iguales

/// </summary>

/// <param name="obj">Objeto vértice a comparar</param>

/// <returns>Verdadero si los nombres son iguales</returns>

protected virtual bool Equals(Vertex obj)

{

return this.Name.Equals(obj.Name);

}

/// <summary>

/// Obtiene un hash code del objeto

/// </summary>

/// <returns>Hash Code del objeto</returns>

public override int GetHashCode()

{

return base.GetHashCode();

}

/// <summary>

/// Entrega la representacion (cadena) del vértice

/// </summary>

/// <returns>Cadena con información dle vértice</returns>

public override string ToString()

{

return String.Format("{0} ({1})", this.Name, this.Number);

}

#endregion

}

}

Page 7: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 6 -

Se sobre escribe el método Equals (heredado de object) con la intención de utilizar para determinar si un vértice es igual a otro; en este caso la igualdad se dará cuando ambos vértices tengan el mismo nombre.

Implementación con matriz de adyacencia

A continuación se describe una implementación (inicial o prototipo) de la estructura de datos grafo utilizando matriz de adyacencia para representar la relación entre vértices.

La estructura interna de la clase debe contener un arreglo de vértices y una matriz de enteros; la clase facilita un mecanismo para numerar los vértices a medida que se agregan al grafo y utilizar este número como índice en la matriz de adyacencia.

using System;

using System.Text;

namespace DemoGrafo1

{

public class GraphMatrix

{

#region Constantes

private const int MAX_VERTEX_NUMBER = 20;

#endregion

#region Estructura Interna y Propiedades

/// <summary>

/// Mantiene el último número de vértices del grafo

/// </summary>

private int _LastVertexNumber;

/// <summary>

/// Accede al último número de vertices del grafo

/// </summary>

protected virtual int LastVertexNumber

{

get { return _LastVertexNumber; }

set { _LastVertexNumber = value; }

}

/// <summary>

/// Mantiene el arreglo de vértices del grafo

/// </summary>

private Vertex[] _Vertexs;

/// <summary>

/// Accede al arreglo de vértices del grafo

/// </summary>

protected virtual Vertex[] Vertexs

{

get { return _Vertexs; }

set { _Vertexs = value; }

}

/// <summary>

/// Mantiene la matriz de adyacencia del grafo

/// </summary>

Page 8: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 7 -

private int[,] _AdyacencyMatrix;

/// <summary>

/// Accede a la matriz de adyacencia del grafo

/// </summary>

protected virtual int[,] AdyacencyMatrix

{

get { return _AdyacencyMatrix; }

set { _AdyacencyMatrix = value; }

}

#endregion

#region Constructores

/// <summary>

/// Constructor por defecto

/// </summary>

public GraphMatrix()

: this(MAX_VERTEX_NUMBER)

{

}

/// <summary>

/// Constructor especializado

/// </summary>

/// <param name="maxVertexNumber">Número máximo de vértices</param>

public GraphMatrix(int maxVertexNumber)

{

if (maxVertexNumber <= 0)

{

throw new Exception(String.Format("Argumento inválido

maxVertexNumber {0}", maxVertexNumber));

}

this.Vertexs = new Vertex[maxVertexNumber];

this.AdyacencyMatrix = new int[maxVertexNumber, maxVertexNumber];

this.LastVertexNumber = 0;

for (int i = 0; i < Vertexs.Length; ++i)

{

for (int j = 0; j < Vertexs.Length; ++j)

{

AdyacencyMatrix[i,j] = 0;

}

}

}

#endregion

#region Utilitario

/// <summary>

/// Busca el número de un vértice de acuerdo a su nombre

/// </summary>

/// <param name="name">Nombre del vértice a buscar</param>

/// <returns>Número del vértice si existe, caso contrario -

1</returns>

public virtual int VertexNumber(String name)

{

return VertexNumber(new Vertex(name));

}

/// <summary>

/// Busca el número de un vértice

/// </summary>

Page 9: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 8 -

/// <param name="name">Vértice a buscar</param>

/// <returns>Número del vertice si existe, caso contrario -

1</returns>

public virtual int VertexNumber(Vertex vertex)

{

for (int i = 0; i < LastVertexNumber; ++i)

{

if (Vertexs[i].Equals(vertex))

{

return Vertexs[i].Number;

}

}

return -1;

}

#endregion

#region Comportamiento básico

public virtual void AddVertex(String name)

{

if (LastVertexNumber == Vertexs.Length)

{

throw new Exception("El grafo ya tiene todos sus vértices");

}

Vertex vertex = new Vertex(name);

if (!(VertexNumber(vertex) >= 0))

{

vertex.Number = LastVertexNumber;

Vertexs[LastVertexNumber] = vertex;

++LastVertexNumber;

}

}

/// <summary>

/// Agrega un arco al grafo

/// </summary>

/// <param name="origin">Nro del vértice origen</param>

/// <param name="destination">Nro del vértice destino</param>

public virtual void AddArch(int origin, int destination)

{

if ((origin < 0) || (origin >= LastVertexNumber) || (destination <

0) || (destination >= LastVertexNumber))

{

throw new Exception(String.Format("Argumento inválido origin {0},

destination {1}", origin, destination));

}

AdyacencyMatrix[origin, destination] = 1;

}

/// <summary>

/// Agrega un arco al grafo

/// </summary>

/// <param name="origin">Nombre del vértice origen</param>

/// <param name="destination">Nombre del vértice destino</param>

public virtual void AddArch(String origin, String destination)

{

AddArch(VertexNumber(origin), VertexNumber(destination));

}

/// <summary>

/// Determina si un vértice es adyacente de otro

Page 10: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 9 -

/// </summary>

/// <param name="origin">Nro del vértice origen</param>

/// <param name="destination">Nro del vértice destino</param>

/// <returns>Verdadero si el vértice origen es adyacente a vértice

destino</returns>

public virtual Boolean Adyacent(int origin, int destination)

{

if ((origin < 0) || (origin >= LastVertexNumber) || (destination <

0) || (destination >= LastVertexNumber))

{

throw new Exception(String.Format("Argumento inválido origin {0},

destination {1}", origin, destination));

}

return AdyacencyMatrix[origin, destination] == 1;

}

/// <summary>

/// Detemrina si un vértice es adyacente a otro

/// </summary>

/// <param name="origin">Nombre del vértice origen</param>

/// <param name="destination">Nombre del vértice destino</param>

/// <returns>Verdadero si el vértice origen es adyacente a vértice

destino</returns>

public virtual Boolean Adyacent(String origin, String destination)

{

return Adyacent(VertexNumber(origin), VertexNumber(destination));

}

#endregion

#region Heredado de object

public override string ToString()

{

StringBuilder sb = new StringBuilder();

for (int i = 0; i < LastVertexNumber; ++i)

{

sb.AppendLine(Vertexs[i].ToString());

}

for (int i = 0; i < LastVertexNumber; ++i)

{

for (int j = 0; j < LastVertexNumber; ++j)

{

sb.AppendFormat("{0,3}", AdyacencyMatrix[i, j]);

}

sb.AppendLine();

}

sb.AppendLine();

return sb.ToString();

}

#endregion

}

}

Código para probar la implementación

A continuación se muestra un pequeña código cliente que permite probar la implementación de grafo con matriz de adyacencia:

Page 11: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 10 -

using System;

namespace DemoGrafo1

{

class Program

{

static void Main(string[] args)

{

// V = {C,D,E,F,H }

// A = {(C,D), (D,F), (E,H), (H,E), (E,C)}

GraphMatrix grafo = new GraphMatrix(5);

grafo.AddVertex("C");

grafo.AddVertex("D");

grafo.AddVertex("E");

grafo.AddVertex("F");

grafo.AddVertex("H");

grafo.AddArch("C", "D");

grafo.AddArch("D", "F");

grafo.AddArch("E", "H");

grafo.AddArch("H", "E");

grafo.AddArch("E", "C");

Console.Write(grafo.ToString());

}

}

}

La estructura de datos realizada nos permite representar lo mínimo que un tipo de dato abstracto grafo tiene, que son sus vértices y las relaciones que existen entre ellos. Se cuenta con mecanismos (métodos) para agregar vértices y arcos así como determinar si dos vértices son o no adyacentes.

Presenta algunos problemas, entre ellos la necesidad de conocer la cantidad de vértices antes de crear (instanciar) un objeto grafo, lo que no es tan grave en los lenguajes orientados a objetos dado que se puede implementar un método que "agrande" el arreglo de vértices y la matriz de adyacencia.

Otro problema es que solamente se puede representar un único arco o arista entre dos vértices; imaginemos una empresa de colectivos que realiza varios viajes por día entre dos localidades de una región, inevitablemente necesita indicar los horarios de cada viaje y en términos de la estructura de datos hace falta asociar "algo" a la matriz de adyacencia.

Implementación con lista de adyacencia

En esta implementación cada vértice del grafo tiene asociada una lista de arcos que indica qué vértices son adyacentes a él. Obviamente hace falta declarar la clase arco.

Page 12: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 11 -

La clase arco (Arch.cs)

namespace DemoGrafo2

{

public class Arch

{

#region Estructura interna y propiedades

/// <summary>

/// Mantiene la referencia al vértice destino

/// </summary>

private Vertex _Destination;

/// <summary>

/// Accede al Nro. de vértice destino

/// </summary>

public Vertex Destination

{

get { return _Destination; }

set { _Destination = value; }

}

#endregion

#region Constructores

/// <summary>

/// Constructor por defecto

/// </summary>

public Arch()

{

Destination = default(Vertex);

}

/// <summary>

/// Constructor especializado, fija el Nro. del vértice destino

/// </summary>

/// <param name="destination">Nro. del vértice destino</param>

public Arch(Vertex destination)

: this()

{

Destination = destination;

}

#endregion

}

}

La clase vértice (Vertex.cs)

Esta variante de la clase vértice contiene la lista de arcos para cada vértice.

using System;

using System.Collections.Generic;

using System.Text;

namespace DemoGrafo2

{

Page 13: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 12 -

public class Vertex

{

#region Estructura Interna y Propiedades

/// <summary>

/// Mantiene el nombre del vértice

/// </summary>

private String _Name;

/// <summary>

/// Accede al nombre del vértice

/// </summary>

public virtual String Name

{

get { return _Name; }

set { _Name = value; }

}

/// <summary>

/// Mantiene el número del vértice

/// </summary>

private int _Number;

/// <summary>

/// Accede al número del vertice

/// </summary>

public virtual int Number

{

get { return _Number; }

set { _Number = value; }

}

/// <summary>

/// Mantiene la lista de arcos del vértice

/// </summary>

private List<Arch> _ArchList;

/// <summary>

/// Accede a la lista de arcos del vértice

/// </summary>

public List<Arch> ArchList

{

get { return _ArchList; }

set { _ArchList = value; }

}

#endregion

#region Constructores

/// <summary>

/// Constructor por defecto

/// </summary>

public Vertex()

{

Name = String.Empty;

Number = -1;

ArchList = new List<Arch>();

}

/// <summary>

/// Constructor especializado

/// </summary>

/// <param name="name">Nombre del vértice</param>

public Vertex(String name)

: this()

Page 14: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 13 -

{

Name = name;

}

/// <summary>

/// Constructor especializado

/// </summary>

/// <param name="name">Nombre del vértice</param>

/// <param name="number">Número del vértice</param>

public Vertex(String name, int number)

: this()

{

Name = name;

Number = number;

}

#endregion

#region Heredado de object

/// <summary>

/// Determina si un vértice es igual a otro

/// </summary>

/// <param name="obj">Objeto a comparar</param>

/// <returns>Verdadero si son iguales</returns>

public override bool Equals(object obj)

{

if ((obj != null) && (obj is Vertex))

{

return Equals((Vertex)obj);

}

throw new Exception(String.Format("No se puede comparar con obj =

{0}", (obj == null ? "null" : obj.GetType().ToString())));

}

/// <summary>

/// Determina si dos vértices son iguales

/// </summary>

/// <param name="obj">Objeto vértice a comparar</param>

/// <returns>Verdadero si los nombres son iguales</returns>

protected virtual bool Equals(Vertex obj)

{

return this.Name.Equals(obj.Name);

}

/// <summary>

/// Obtiene un hash code del objeto

/// </summary>

/// <returns>Hash Code del objeto</returns>

public override int GetHashCode()

{

return base.GetHashCode();

}

/// <summary>

/// Entrega la representacion (cadena) del vértice

/// </summary>

/// <returns>Cadena con información dle vértice</returns>

public override string ToString()

{

StringBuilder sb = new StringBuilder();

sb.AppendFormat("{0} ({1}) - ", this.Name, this.Number);

foreach (Arch a in ArchList)

Page 15: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 14 -

{

sb.AppendFormat(" {0}", a.Destination.Name);

}

sb.AppendLine();

return sb.ToString();

}

#endregion

}

}

La clase Grafo con Lista de Adyacencia (GraphList.cs)

Esta estructura de datos implementa el tipo de dato abstracto grafo utilizando lista de adyacencia.

using System;

using System.Text;

namespace DemoGrafo2

{

public class GraphList

{

#region Constantes

private const int MAX_VERTEX_NUMBER = 20;

#endregion

#region Estructura Interna y Propiedades

/// <summary>

/// Mantiene el último número de vértices del grafo

/// </summary>

private int _LastVertexNumber;

/// <summary>

/// Accede al último número de vertices del grafo

/// </summary>

protected virtual int LastVertexNumber

{

get { return _LastVertexNumber; }

set { _LastVertexNumber = value; }

}

/// <summary>

/// Mantiene el arreglo de vértices del grafo

/// </summary>

private Vertex[] _Vertexs;

/// <summary>

/// Accede al arreglo de vértices del grafo

/// </summary>

protected virtual Vertex[] Vertexs

{

get { return _Vertexs; }

set { _Vertexs = value; }

}

#endregion

#region Constructores

/// <summary>

Page 16: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 15 -

/// Constructor por defecto

/// </summary>

public GraphList()

: this(MAX_VERTEX_NUMBER)

{

}

/// <summary>

/// Constructor especializado

/// </summary>

/// <param name="maxVertexNumber">Número máximo de vértices</param>

public GraphList(int maxVertexNumber)

{

if (maxVertexNumber <= 0)

{

throw new Exception(String.Format("Argumento inválido

maxVertexNumber {0}", maxVertexNumber));

}

this.Vertexs = new Vertex[maxVertexNumber];

this.LastVertexNumber = 0;

}

#endregion

#region Utilitario

/// <summary>

/// Busca el número de un vértice de acuerdo a su nombre

/// </summary>

/// <param name="name">Nombre del vértice a buscar</param>

/// <returns>Número del vértice si existe, caso contrario -

1</returns>

public virtual int VertexNumber(String name)

{

return VertexNumber(new Vertex(name));

}

/// <summary>

/// Busca el número de un vértice

/// </summary>

/// <param name="name">Vértice a buscar</param>

/// <returns>Número del vertice si existe, caso contrario -

1</returns>

public virtual int VertexNumber(Vertex vertex)

{

for (int i = 0; i < LastVertexNumber; ++i)

{

if (Vertexs[i].Equals(vertex))

{

return Vertexs[i].Number;

}

}

return -1;

}

#endregion

#region Comportamiento básico

public virtual void AddVertex(String name)

{

if (LastVertexNumber == Vertexs.Length)

{

Page 17: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 16 -

throw new Exception("El grafo ya tiene todos sus vértices");

}

Vertex vertex = new Vertex(name);

if (!(VertexNumber(vertex) >= 0))

{

vertex.Number = LastVertexNumber;

Vertexs[LastVertexNumber] = vertex;

++LastVertexNumber;

}

}

/// <summary>

/// Agrega un arco al grafo

/// </summary>

/// <param name="origin">Nro del vértice origen</param>

/// <param name="destination">Nro del vértice destino</param>

public virtual void AddArch(int origin, int destination)

{

if ((origin < 0) || (origin >= LastVertexNumber) || (destination <

0) || (destination >= LastVertexNumber))

{

throw new Exception(String.Format("Argumento inválido origin {0},

destination {1}", origin, destination));

}

Vertexs[origin].ArchList.Add(new Arch(Vertexs[destination]));

}

/// <summary>

/// Agrega un arco al grafo

/// </summary>

/// <param name="origin">Nombre del vértice origen</param>

/// <param name="destination">Nombre del vértice destino</param>

public virtual void AddArch(String origin, String destination)

{

AddArch(VertexNumber(origin), VertexNumber(destination));

}

/// <summary>

/// Determina si un vértice es adyacente de otro

/// </summary>

/// <param name="origin">Nro del vértice origen</param>

/// <param name="destination">Nro del vértice destino</param>

/// <returns>Verdadero si el vértice origen es adyacente a vértice

destino</returns>

public virtual Boolean Adyacent(int origin, int destination)

{

if ((origin < 0) || (origin >= LastVertexNumber) || (destination <

0) || (destination >= LastVertexNumber))

{

throw new Exception(String.Format("Argumento inválido origin {0},

destination {1}", origin, destination));

}

foreach (Arch a in Vertexs[origin].ArchList)

{

if (a.Destination.Number == destination)

{

return true;

}

}

return false;

Page 18: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 17 -

}

/// <summary>

/// Detemrina si un vértice es adyacente a otro

/// </summary>

/// <param name="origin">Nombre del vértice origen</param>

/// <param name="destination">Nombre del vértice destino</param>

/// <returns>Verdadero si el vértice origen es adyacente a vértice

destino</returns>

public virtual Boolean Adyacent(String origin, String destination)

{

return Adyacent(VertexNumber(origin), VertexNumber(destination));

}

#endregion

#region Heredado de object

public override string ToString()

{

StringBuilder sb = new StringBuilder();

for (int i = 0; i < LastVertexNumber; ++i)

{

sb.AppendLine(Vertexs[i].ToString());

}

return sb.ToString();

}

#endregion

}

}

Código para probar la implementación

A continuación se muestra un pequeña código cliente que permite probar la implementación de grafo con lista de adyacencia:

using System;

namespace DemoGrafo2

{

class Program

{

static void Main(string[] args)

{

// V = {C,D,E,F,H }

// A = {(C,D), (D,F), (E,H), (H,E), (E,C)}

GraphList grafo = new GraphList(5);

grafo.AddVertex("C");

grafo.AddVertex("D");

grafo.AddVertex("E");

grafo.AddVertex("F");

grafo.AddVertex("H");

Page 19: Estructura de Datos y Grafos

Estructura de Datos y Grafos

- 18 -

grafo.AddArch("C", "D");

grafo.AddArch("D", "F");

grafo.AddArch("E", "H");

grafo.AddArch("H", "E");

grafo.AddArch("E", "C");

Console.Write(grafo.ToString());

}

}

}

El mismo comportamiento

Es importante destacar que sea cual sea la implementación (al menos las realizadas hasta el momento) presentan el mismo comportamiento (los mismos métodos)

Salvo los constructores, ambas estructuras de datos presentan los mismo métodos

Continuar la declaración de las estructuras de datos que implementan el tipo de dato abstracto grafo no es complicado y se deja para las prácticas.