2009-11-15 20 views
35

Estoy implementando algunos algoritmos para enseñarme acerca de los gráficos y cómo trabajar con ellos. ¿Cuál recomendarías es la mejor manera de hacerlo en Java? Estaba pensando algo así:Java: ¿cómo representar gráficos?

public class Vertex { 

    private ArrayList<Vertex> outnodes; //Adjacency list. if I wanted to support edge weight, this would be a hash map. 

    //methods to manipulate outnodes 
} 

public class Graph { 
    private ArrayList<Vertex> nodes; 
    //algorithms on graphs 
} 

Pero básicamente lo inventé. ¿Hay una mejor manera?

Además, quiero que sea capaz de soportar las variaciones en los gráficos de vainilla como dígrafos, bordes ponderados, multigrafos, etc.

+0

¿Qué fue con qué empezar? Me estoy preparando para una prueba, me queda un día.Tendré que escribir un programa para una pequeña cantidad de nodos. También pensé de la misma manera que tú. –

Respuesta

13

Si necesita bordes ponderados y multigrafos, es posible que desee añadir otra clase Edge .

También recomendaría utilizar genéricos para permitir especificar qué subclase de Vertex y Edge se utilizan actualmente. Por ejemplo:

public class Graph<V extends Vertex> { 
List<V> vertices; 
... 
} 

Cuando se trata de implementar algoritmos de grafos, también se podría definir interfaces de para sus clases gráfico en el que los algoritmos pueden funcionar, por lo que se puede jugar con diferentes implementaciones de la representación real gráfico . Por ejemplo, los gráficos simples que están bien conectados se puede aplicar mejor por un adjacency matrix, gráficos más dispersas podrían ser representados por adjacency lists - todo depende ...

BTW La construcción de estas estructuras de manera eficiente puede ser bastante difícil, Entonces, ¿podría darnos más detalles sobre el tipo de trabajo para el que desea usarlos? Para tareas más complejas, le sugiero que eche un vistazo a las diversas bibliotecas de gráficos de Java, para obtener algo de inspiración.

+0

Realmente no tengo ningún detalle ... mis objetivos de autoaprendizaje son bastante abiertos. Solo quiero configurar algunos gráficos, buscar algunos árboles de expansión mínima, hacer alguna salida a graphviz, calcular el tipo topológico, etc. –

+0

y ¿puedes aclarar cómo usarías los genéricos? –

+0

Ah, gracias por la aclaración. Si es solo por jugar, creo que las listas de adyacencia harán el trabajo ... no parece que requiera mucho rendimiento. Espero haber aclarado la parte de los genéricos. –

5

Eche un vistazo a la biblioteca de gráficos http://jung.sourceforge.net/doc/index.html. Aún puede practicar la implementación de sus propios algoritmos (tal vez la búsqueda de ancho primero o profundidad primero para comenzar), pero no necesita preocuparse por crear la estructura de gráfico.

+1

bfs y dfs en gráficos? – Kay

+0

@Kay, Sí, DFS y BFS en gráficos: https://www.youtube.com/watch?v=zaBhtODEL0w – Randy

2

Hace un tiempo tuve el mismo problema e hice mi propia implementación. Lo que sugiero es implementar otra clase: Edge. Entonces, un Vertex tendrá una Lista de bordes.

public class Edge { 
    private Node a, b; 
    private directionEnum direction;  // AB, BA or both 
    private int weight; 
    ... 
} 

Me funcionó. Pero tal vez es tan simple. Existe esta biblioteca que quizás pueda ayudarlo si nos fijamos en su código: http://jgrapht.sourceforge.net/

2

Recomendaría graphviz cuando llegue al punto en el que desea representar sus gráficos.

Y sus acompañantes: eche un vistazo a Laszlo Szathmary's GraphViz class, junto con notugly.xls.

+0

graphviz es legítimo. ¿Recomienda algo para que sea más fácil pasar de una estructura de datos Java a un archivo graphviz.dot, y posiblemente generar la imagen directamente desde Java? –

+0

Sí, eche un vistazo a la clase GraphViz de Laszlo Szathmary: http: //www.vclcomponents.com/Java/Scripts_and_Programs/Miscellaneous/GraphViz_Java_API-info.html, junto con notugly.xls: http://www.hokstad.com/ making-graphviz-output-pretty-with-xsl.html – duffymo

+0

Laszlo es bueno, pero me da una excepción de puntero nulo cuando ejecuto la demostración. No muy alentador. –

2

Incluso en el momento de esta pregunta, hace más de 3 años, existía Sage (que es completamente gratuito) y era bastante bueno en la teoría de grafos. Pero, en 2012, se trata de la mejor herramienta de teoría de grafos que existe. Por lo tanto, Sage ya tiene una gran cantidad de material de teoría de gráficos integrado, incluidas otras cosas de código abierto y gratuito que están disponibles. Entonces, simplemente jugar con varias cosas para aprender más es fácil ya que no se requiere programación.

Y, si también está interesado en la parte de programación, primero Sage es de código abierto para que pueda ver cualquier código que ya exista.Y, en segundo lugar, puede volver a programar cualquier función que desee si realmente desea practicar, o puede ser el primero en programar algo que aún no existe. En el último caso, incluso puede enviar esa nueva funcionalidad y hacer que Sage sea mejor para todos los demás usuarios.

En este momento, esta respuesta puede no ser tan útil para el OP (ya que han pasado 3 años), pero es de esperar que sea útil para cualquier otra persona que vea esta pregunta en el futuro.

0

La implementación de la lista de adyacencia de Graph es adecuada para resolver la mayoría de los problemas relacionados con el gráfico.

La implementación de Java de la misma es here en mi blog.

0
class Graph<E> { 
    private List<Vertex<E>> vertices; 

    private static class Vertex<E> { 
     E elem; 
     List<Vertex<E>> neighbors; 
    } 
} 
-1
class Vertex { 
    private String name; 
    private int score; // for path algos 
    private boolean visited; // for path algos 
    List<Edge> connections; 
} 

class Edge { 
    private String vertex1Name; // same as Vertex.name 
    private String vertex2Name; 
    private int length; 
} 

class Graph { 
    private List<Edge> edges; 
} 
+1

Su borde solo conoce el nombre del Vértice. Como tal, no podría atravesar el gráfico con la estructura que ha mostrado. – bhspencer

+0

Con la lógica adicional de recrear el nodo a partir de su nombre, aún podríamos hacer el recorrido. Hice esto a favor de ahorrar espacio para que no tengamos que guardar los vértices completos nuevamente en Edge. Es como guardar solo la clave principal en una tabla extraña. – Mustafa

+2

Cuando un objeto tiene una referencia a otro objeto como miembro de la clase, no guarda allí el objeto completo. Es solo un puntero al otro objeto. No hay duplicación de datos si, por ejemplo, dos bordes hacen referencia al mismo vértice. – bhspencer

13

Cada nodo es un nombre exclusivo y sabe quién está conectado. La Lista de conexiones permite que un Nodo se conecte a un número arbitrario de otros nodos.

public class Node { 
    public String name; 
    public List<Edge> connections; 
} 

Cada conexión está dirigida, tiene un principio y un fin, y está ponderada.

public class Edge { 
    public Node start; 
    public Node end; 
    public double weight; 
} 

Un gráfico es sólo su colección de nodos. En lugar de List<Node> considere Map<String, Node> para búsqueda rápida por nombre.

public class Graph { 
    List<Node> nodes; 
} 
+0

Quizás sea mejor nombrar las conexiones como vecinos. Además, si no usamos los bordes por separado, ya conocemos su punto de inicio, por lo que uno puede eliminarlo para la mayoría de los casos de uso para que sea más eficiente en cuanto al espacio – mCeviker

+0

Puedo imaginar un gráfico que no incluya los bordes. Si no necesita pesas en los bordes o no necesita dirección, podría ser una simplificación fina. – bhspencer

+0

Quiero decir que debemos incluir los bordes como una lista, es una buena estrategia para la mayoría de los problemas, pero puede que no necesitemos el objeto "Inicio de nodo" en el objeto de borde, porque al atravesar nodos del gráfico sabemos que el nodo atravesado es comienzo. Por cierto, las conexiones se pueden cambiar a "bordes", mi sugerencia de vecinos es un nombre peor :( – mCeviker

0

Una simple representación escrita por Robert Sedgwick 'y 'Kevin Wayne' está disponible en http://algs4.cs.princeton.edu/41graph/Graph.java.html

Explicación copiado de la página anterior.

La clase gráfico representa un grafo no dirigido de vértices nombradas 0 a través de V - 1.

Es compatible con los siguientes dos operaciones principales: añadir un borde a la gráfica, iterar sobre todo de la vértices adyacentes a un vértice. También proporciona métodos para devolver el número de vértices V y el número de bordes E. Se permiten bordes paralelos y bucles automáticos. Por convención, una auto-loop v - v aparece en la lista de adyacencia v dos veces y dos contribuye al grado de v.

Esta implementación utiliza una representación de listas de adyacencia, que es una matriz indexada en vértices de objetos Bag. Todas las operaciones toman un tiempo constante (en el peor de los casos) excepto iterando sobre los vértices adyacentes a un vértice dado, lo que toma tiempo proporcional al número de dichos vértices.

Cuestiones relacionadas