Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Aug 5th, 2012  |  syntax: None  |  size: 6.77 KB  |  hits: 12  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. import java.util.ArrayList;
  2. import java.util.HashSet;
  3. import java.util.LinkedHashSet;
  4. import java.util.List;
  5. import java.util.Set;
  6.  
  7. /**
  8.  *
  9.  * A generic directed graph that doesn't allow duplicate elements and performs
  10.  * topological sorting to detect cycles. All primitive operations are done in
  11.  * linear time. Sorting is done in polynomial time at most.
  12.  *
  13.  * @author Ryan Beckett
  14.  */
  15. public class GraphSet<T> {
  16.  
  17.     private HashSet<Vertex<T>> graph = new HashSet<Vertex<T>>();
  18.  
  19.     /**
  20.      * Add a new element to the graph.
  21.      *
  22.      * @param elem
  23.      *            The element to be added to the graph.
  24.      * @return <code>true</code> if the graph was changed as a result of this
  25.      *         operation, otherwise <code>false</code>.
  26.      */
  27.     public boolean add(T elem) {
  28.         if (get(elem) != null)
  29.             return false;
  30.         return graph.add(new Vertex<T>(elem));
  31.     }
  32.  
  33.     /**
  34.      * Create an edge between two elements. <code>src</code> and
  35.      * <code>dest<code> must exist.
  36.      *
  37.      * @param src
  38.      *            The source vertex.
  39.      * @param dest
  40.      *            The destination vertex.
  41.      * @return <code>true</code> if the graph was changed as a result of this
  42.      *         operation, otherwise <code>false</code>.
  43.      */
  44.     public boolean newEdge(T src, T dest) {
  45.         Vertex<T> srcVertex = get(src);
  46.         Vertex<T> destVertex = get(dest);
  47.         if (srcVertex == null || destVertex == null)
  48.             return false;
  49.         for (Vertex<T> vertex : graph)
  50.             if (vertex.elem.equals(src))
  51.                 return vertex.newNeighbor(destVertex);
  52.         return false;
  53.     }
  54.  
  55.     /**
  56.      * Remove an edge between two elements. <code>src</code> and
  57.      * <code>dest<code> must exist.
  58.      *
  59.      * @param src
  60.      *            The source vertex.
  61.      * @param dest
  62.      *            The destination vertex.
  63.      * @return <code>true</code> if the graph was changed as a result of this
  64.      *         operation, otherwise <code>false</code>.
  65.      */
  66.     public boolean removeEdge(T src, T dest) {
  67.         Vertex<T> srcVertex = get(src);
  68.         Vertex<T> destVertex = get(dest);
  69.         if (srcVertex == null || destVertex == null)
  70.             return false;
  71.         for (Vertex<T> vertex : graph)
  72.             if (vertex.elem.equals(src))
  73.                 return vertex.removeNeighbor(destVertex);
  74.         return false;
  75.     }
  76.  
  77.     private Vertex<T> get(T elem) {
  78.         for (Vertex<T> vertex : graph)
  79.             if (vertex.elem.equals(elem))
  80.                 return vertex;
  81.         return null;
  82.     }
  83.  
  84.     /**
  85.      * Remove the specified element from the graph.
  86.      *
  87.      * @param elem
  88.      *            The element to be removed from the graph.
  89.      * @return <code>true</code> if the graph was changed as a result of this
  90.      *         operation, otherwise <code>false</code>.
  91.      */
  92.     public boolean remove(T elem) {
  93.         Vertex<T> removeVertex = get(elem);
  94.         if (removeVertex == null)
  95.             return false;
  96.         for (Vertex<T> vertex : graph)
  97.             vertex.removeNeighbor(removeVertex);
  98.         return graph.remove(removeVertex);
  99.     }
  100.  
  101.     /**
  102.      * Return a string representation of the graph.
  103.      *
  104.      * @return A string representation of the graph.
  105.      */
  106.     public String toString() {
  107.         StringBuilder sb = new StringBuilder();
  108.         for (Vertex<T> vertex : graph) {
  109.             sb.append(vertex.elem + "->" + vertex.neighbors.toString() + "\n");
  110.         }
  111.         return sb.toString();
  112.     };
  113.  
  114.     /**
  115.      * Performs a topological sort on the graph.
  116.      *
  117.      * @return A list of elements in topological order or <code>null</code> if
  118.      *         the graph has a cycle.
  119.      */
  120.     @SuppressWarnings("unchecked")
  121.     public List<T> sort() {
  122.         List<Vertex<T>> sortedVertices = new ArrayList<Vertex<T>>();
  123.         Set<Vertex<T>> noSrcVertices = findVerticesWithNoSrcEdges();
  124.         while (noSrcVertices.size() > 0) {
  125.             Vertex<T> vertex = (Vertex<T>) noSrcVertices.toArray()[0];
  126.             noSrcVertices.remove(vertex);
  127.             sortedVertices.add(vertex);
  128.             Object[] neighbors = vertex.neighbors.toArray();
  129.             for (int i = 0; i < neighbors.length; i++) {
  130.                 Vertex<T> neighbor = (Vertex<T>) neighbors[i];
  131.                 removeEdge(vertex.elem, neighbor.elem);
  132.                 if (!hasSrcEdges(neighbor))
  133.                     noSrcVertices.add(neighbor);
  134.             }
  135.         }
  136.         if (graphHasEdges())
  137.             return null;
  138.         else {
  139.             ArrayList<T> sortedElems = new ArrayList<T>();
  140.             for (Vertex<T> vertex : sortedVertices)
  141.                 sortedElems.add(vertex.elem);
  142.             return sortedElems;
  143.         }
  144.  
  145.     }
  146.  
  147.     /**
  148.      * Check whether the graph has edges.
  149.      */
  150.     private boolean graphHasEdges() {
  151.         for (Vertex<T> vertex : graph)
  152.             if (vertex.neighbors.size() > 0)
  153.                 return true;
  154.         return false;
  155.     }
  156.  
  157.     /**
  158.      * Build a list of vertices without incoming edges.
  159.      */
  160.     private Set<Vertex<T>> findVerticesWithNoSrcEdges() {
  161.         LinkedHashSet<Vertex<T>> noSrcElems = new LinkedHashSet<Vertex<T>>();
  162.         for (Vertex<T> vertex : graph)
  163.             if (!hasSrcEdges(vertex))
  164.                 noSrcElems.add(vertex);
  165.         return noSrcElems;
  166.     }
  167.  
  168.     /**
  169.      * Check whether the vertex has an incoming edge.
  170.      */
  171.     private boolean hasSrcEdges(Vertex<T> vertex) {
  172.         for (Vertex<T> currVertex : graph)
  173.             if (currVertex.isNeighbor(vertex))
  174.                 return true;
  175.         return false;
  176.     }
  177.  
  178.     private static class Vertex<E> {
  179.  
  180.         E elem;
  181.         HashSet<Vertex<E>> neighbors = new HashSet<Vertex<E>>();
  182.  
  183.         Vertex(E elem) {
  184.             this.elem = elem;
  185.         }
  186.  
  187.         boolean newNeighbor(Vertex<E> vertex) {
  188.             return neighbors.add(vertex);
  189.         }
  190.  
  191.         boolean isNeighbor(Vertex<E> vertex) {
  192.             return neighbors.contains(vertex);
  193.         }
  194.  
  195.         boolean removeNeighbor(Vertex<E> vertex) {
  196.             return neighbors.remove(vertex);
  197.         }
  198.  
  199.         @SuppressWarnings("unchecked")
  200.         public boolean equals(Object o) {
  201.             Vertex<E> other = (Vertex<E>) o;
  202.             return elem.equals(other.elem);
  203.         }
  204.  
  205.         public String toString() {
  206.             return elem.toString();
  207.         }
  208.     }
  209.  
  210.     public static void main(String[] args) {
  211.  
  212.         GraphSet<Integer> graph = new GraphSet<Integer>();
  213.         graph.add(1);
  214.         graph.add(2);
  215.         graph.add(3);
  216.         graph.add(4);
  217.         graph.add(5);
  218.         graph.add(6);
  219.  
  220.         graph.newEdge(1, 2);
  221.         graph.newEdge(1, 4);
  222.         graph.newEdge(4, 2);
  223.         graph.newEdge(5, 4);
  224.         graph.newEdge(3, 5);
  225.         graph.newEdge(3, 6);
  226.  
  227.         System.out.println(graph);
  228.  
  229.         // create cycle and fail sort
  230.         // graph.newEdge(6, 6);
  231.  
  232.         System.out.println(graph.sort());
  233.     }
  234. }