Beispiel #1
0
  /**
   * parallel MST algorithm based on Boruvka's algorithm.
   *
   * @param <E> value type of the node in the target graph
   * @param graph the graph to compute minimum spanning tree
   * @param pool external thread pool
   * @return a minimum spanning tree in the form of undirected graph
   * @throws InterruptedException thrown exception if be interrupted
   * @throws ExecutionException Exception thrown when attempting to retrieve the result of a task
   *     that aborted by throwing an exception
   */
  public static <E> Graph<E> getMST(final UndirectedGraph graph, ExecutorService pool)
      throws InterruptedException, ExecutionException {
    if (!(graph instanceof UndirectedGraph)) {
      throw new IllegalArgumentException("graph is not an undirected graph");
    }

    final Graph<E> mst = new UndirectedGraph<E>();
    Collection<Node<E>> nodes = graph.getAllNodes();
    final Collection<Node<E>> graphNodes = graph.getAllNodes();

    int size = nodes.size();
    Runnable[] tasks = new Runnable[size];

    int index = 0;

    final ConcurrentHashMap<Node<E>, Collection<Edge<E>>> edges =
        new ConcurrentHashMap<Node<E>, Collection<Edge<E>>>();

    // step 0: init , get all the edge list and store them in map edges and
    // add all node into mst
    Iterator<Node<E>> it = nodes.iterator();
    while (it.hasNext()) {
      final Node<E> n = it.next();
      tasks[index++] =
          new Runnable() {
            public void run() {
              Collection<Edge<E>> edge = graph.getLinkedEdges(n);
              edges.put(n, edge);
              mst.addNode(n.getValue());
            }
          };
    }
    runTasks(tasks, 0, index, pool);

    final AtomicBoolean finish = new AtomicBoolean(false);
    final ConcurrentHashMap<Node<E>, Node<E>> roots = new ConcurrentHashMap<Node<E>, Node<E>>();

    while ((size = (nodes = edges.keySet()).size()) > 1) {
      // System.out.println("222 " + size);
      Iterator<Node<E>> iter = nodes.iterator();
      index = 0;
      // final CountDownLatch wait = new CountDownLatch(size);

      while (iter.hasNext()) {
        final Node<E> cur = iter.next();

        // step 1:find lightest edge to each vertex , add it to
        // the new graph and remove it
        tasks[index++] =
            new Runnable() {
              public void run() {
                Edge<E> e = getMinimumEdgeWith(edges, cur);
                if (e == null) {
                  finish.set(true);
                  return;
                }
                Node<E> end = e.getEnd();
                Node<E> start = e.getStart();

                Node<E> n = roots.get(end);
                Node<E> c = roots.get(start);
                if (n == null) n = end;
                if (c == null) c = start;

                // merge the two trees. we vote the node with small
                // compare as root
                int cmp = n.compareTo(c);
                // if (cmp > 0) {
                // Node<E> v = roots.putIfAbsent(n, c);
                // } else if (cmp < 0) {
                // Node<E> v = roots.putIfAbsent(c, n);
                //						}

                if (cmp != 0) mst.addEdge(start, end, e.getWeight());
              }
            };
      }
      runTasks(tasks, 0, index, pool);
      if (finish.get()) throw new IllegalArgumentException("graph is not a connected graph");

      // step 2: find parent
      Enumeration<Node<E>> enu = roots.keys();
      index = 0;
      while (enu.hasMoreElements()) {
        // System.out.println("444");
        final Node<E> cur = enu.nextElement();
        tasks[index++] =
            new Runnable() {
              public void run() {
                Node<E> p = cur;
                Node<E> tmp = cur;
                do {
                  p = tmp;
                  tmp = roots.get(tmp);
                } while (tmp != null); // TODO GZ:sometime infinite
                // loop here

                if (cur != p) {
                  roots.put(cur, p);
                }
              }
            };
      }
      runTasks(tasks, 0, index, pool);

      // step 3: rename vertex in original graph and remove the edges;
      index = 0;

      iter = graphNodes.iterator();

      while (iter.hasNext()) {
        // System.out.println("555");
        final Node<E> cur = iter.next();

        tasks[index++] =
            new Runnable() {
              public void run() {
                Node<E> p = roots.get(cur);
                // for every parent, add all children's edgelist and
                // remove all the inner edge
                if (p == null) {
                  Collection<Edge<E>> coll = edges.get(cur);
                  HashSet<Node<E>> children = new HashSet<Node<E>>();

                  Iterator<Node<E>> it = graphNodes.iterator();
                  while (it.hasNext()) {
                    Node<E> n = it.next();
                    if (roots.get(n) == cur) {
                      children.add(n);
                      if (edges.containsKey(n)) {
                        coll.addAll(edges.get(n));
                        edges.remove(n);
                      }
                    }
                  }

                  Iterator<Edge<E>> iterator = coll.iterator();
                  while (iterator.hasNext()) {
                    Edge<E> e = iterator.next();
                    Node<E> end = e.getEnd();
                    if (end.equals(cur) || children.contains(end)) {
                      iterator.remove();
                    }
                  }
                }
              }
            };
      }
      runTasks(tasks, 0, index, pool);
    }

    // remove loop edge in MST
    nodes = mst.getAllNodes();
    index = 0;
    Iterator<Node<E>> iter = nodes.iterator();
    while (iter.hasNext()) {
      final Node<E> cur = iter.next();
      tasks[index++] =
          new Runnable() {
            public void run() {
              // use a hashset to find the same node, pay space for time
              HashSet<Node<E>> sets = new HashSet<Node<E>>();
              Collection<AdjacentNode<E>> lns = mst.getLinkedNodes(cur);
              Iterator<AdjacentNode<E>> iterAdj = lns.iterator();

              AdjacentNode<E> adj;
              while (iterAdj.hasNext()) {
                adj = iterAdj.next();
                Node<E> tar = adj.getNode();
                if (!sets.add(tar)) {
                  iterAdj.remove();
                }
              }
            }
          };
    }
    runTasks(tasks, 0, index, pool);
    return mst;
  }