All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jangaroo.jooc.util.GraphUtil Maven / Gradle / Ivy

There is a newer version: 4.1.17
Show newest version
package net.jangaroo.jooc.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A utility for finding the strongly connected components of a graph,
 * implementing Kosaraju's algorithm non-recursively.
 */
public class GraphUtil {
  public static  Collection> stronglyConnectedComponent(Map> graph) {
    Map> reversed = reverse(graph);

    Map> sccsByRoot = new HashMap>();
    Set assigned = new HashSet();
    for (T root : kosarajuSort(graph)) {
      Deque todo = new LinkedList();
      todo.add(root);
      while (!todo.isEmpty()) {
        T current = todo.removeLast();
        if (assigned.add(current)) {
          Set component = getOrAdd(sccsByRoot, root);
          component.add(current);
          todo.addAll(reversed.get(current));
        }
      }
    }

    return sccsByRoot.values();
  }

  static  Map> reverse(Map> graph) {
    Map> result = new HashMap>();
    for (Map.Entry> entry : graph.entrySet()) {
      T predecessor = entry.getKey();
      getOrAdd(result, predecessor);
      for (T successor : entry.getValue()) {
        Set predecessors = getOrAdd(result, successor);
        predecessors.add(predecessor);
      }
    }
    return result;
  }

  private static  Set getOrAdd(Map> map, T key) {
    Set predecessors = map.get(key);
    if (predecessors == null) {
      predecessors = new HashSet();
      map.put(key, predecessors);
    }
    return predecessors;
  }

  static  Deque kosarajuSort(Map> graph) {
    Set reached = new HashSet();
    Set processed = new HashSet();
    Deque sorted = new LinkedList();

    Deque todo = new LinkedList(graph.keySet());
    while (!todo.isEmpty()) {
      T current = todo.getLast();
      if (reached.add(current)) {
        // New node to be processed.
        Collection successors = graph.get(current);
        if (successors != null) {
          for (T successor : successors) {
            // Make sure to add only successors not already reached,
            // so that membership in the set reached is an indicator of a
            // backtracking step after all successors have been processed.
            if (!reached.contains(successor)) {
              todo.add(successor);
            }
          }
        }
      } else {
        // All successors have been processed.
        todo.removeLast();
        if (processed.add(current)) {
          // The node
          sorted.addFirst(current);
        }
      }
    }
    return sorted;
  }

  /**
   * Find the shortest path from start to end.
   * @param graph
   * @param start
   * @param end
   * @param 
   * @return
   */
  public static  List findPath(Map> graph, T start, T end) {
    // Breadth-first search for the shortest path.
    Map predecessors = new HashMap();
    List todo = new ArrayList();
    todo.add(start);
    while (!todo.isEmpty()) {
      List nextTodo = new ArrayList();
      for (T current : todo) {
        Collection successors = graph.get(current);
        if (successors != null) {
          for (T successor : successors) {
            if (!predecessors.containsKey(successor)) {
              predecessors.put(successor, current);
              nextTodo.add(successor);
            }
          }
        }
      }

      todo = nextTodo;
    }

    List result = new ArrayList();
    result.add(end);
    T current = end;
    do {
      current = predecessors.get(current);
      if (current == null) {
        return null;
      }
      result.add(current);
    } while (!current.equals(start));
    Collections.reverse(result);
    return result;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy