Site Search:

Graph.java that stores circles




import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Graph {
    private Set<Integer> marked = new HashSet<>();
    private Map<Integer, Set<Integer>> neighbors = new HashMap<>();
    private Integer[] edgeTo;
    private Integer start;
    private int count = 0;
    private static String[] colors = {"red", "blue", "green", "purple", "yellow", "brown", "azure",
        "gray", "ivory", "lime", "navy", "oliver", "coral", "cyan", "pink"};
    private boolean hasCircle = false;
    private float thick = 2.0f;
    //key is the start point, value is the set of end points 
    private Map<Integer, Set<Integer>> circles = new HashMap<>();
    
    //position of the pair interchangable
    private class Pair implements Comparable<Pair>{
        @Override
        public String toString() {
            return "Pair [a=" + a + ", b=" + b + "]";
        }
        int a, b;
        public Pair(int a, int b) {
            this.a = a; this.b = b;
        }
        @Override
        public int compareTo(Pair o) {
            return hashCode() - o.hashCode();
        }
        @Override
        public boolean equals(Object o) {
            if(!(o instanceof Pair)) return false;
            Pair p = (Pair)o;
            if((a == p.a && b == p.b) || (a == p.b && b == p.a)) {
                return true;
            } else {
                return false;
            }
        }
        @Override
        public int hashCode() {
            int hash = 23;           
            hash = hash * 31 + (a > b ? a : b);
            hash = hash * 31 + (a > b ? b : a);
            return hash;
        }
    }

    public Set<Integer> getPoints() {
        return neighbors.keySet();
    }

    public int size() {
        return getPoints().size();
    }

    public long edgeSize() {
        return neighbors.values().stream()
                .collect(Collectors.summingLong(Set::size)) / 2;
    }

    public void addEdge(int a, int b) {
        neighbors.computeIfAbsent(a, k -> new HashSet<Integer>()).add(b);
        neighbors.computeIfAbsent(b, k -> new HashSet<Integer>()).add(a);
    }

    public boolean dfsHasCircle(Integer start) {
        this.start = start;
        edgeTo = new Integer[this.size()]; //use map to avoid Index out of bound exception
        this.hasCircle = false;
        dfsCircle(start, start);
        return this.hasCircle;
    }

    public void dfsCircle(Integer v, Integer from) {
        marked.add(v);
        for (Integer w : neighbors.get(v)) {
            if (!marked.contains(w)) {
                edgeTo[w] = v;
                dfsCircle(w, v);
            } else if (!from.equals(w)) {
                this.hasCircle = true;
                circles.computeIfAbsent(w, k -> new HashSet<>()).add(v);
            }
        }
    }
    
    private void printCircle(Integer begin, Integer end) {
        Stack<Integer> stack = new Stack<>();
        boolean rightDirection = false;
        for(Integer i = end; !i.equals(start); i = edgeTo[i]) {
            stack.push(i);
            if(i.equals(begin)) {
                rightDirection = true;
                break;
            }
        }
        if(begin.equals(start)) {
            stack.push(start);
            rightDirection = true;
        }
        if(!rightDirection) {
            stack = new Stack<>();
            for(Integer i = begin; !i.equals(start); i = edgeTo[i]) {
                stack.push(i);
                if(i.equals(end)) {
                    rightDirection = true;
                    break;
                }
            }
        }
        if(end.equals(start)) {
            stack.push(start);
            rightDirection = true;
        }
        if(!rightDirection || stack.isEmpty()) {
            System.out.println("//traversal didn't discover this two points as start and end of a circle:"
        + begin + " " + end);
            return;
        }

        System.out.println("//======circle #" + count + " ========");
        Integer v = stack.pop();
        Integer w;
        while(!stack.isEmpty()) {
            w = stack.pop();
            System.out.printf(v + "--" + w + "[label=" + count
                    + ", color=" + colors[count%colors.length] + ",penwidth=%.1f];\n", thick);
            v = w;
        }
        System.out.printf(begin + "--" + end + "[label=" + count
                + ", color=" + colors[count%colors.length] + ",penwidth=%.1f];\n", thick);
        count++;
        thick+=0.5f;
    }

    public static void main(String... args) {
        Graph g = new Graph();
        // change the number of points and edges here.
        for (int i = 0; i < 7; i++) {
            g.addEdge(i, i + 1);
            g.addEdge(i, i + 2);
        }
        for (int i = 15; i < 17; i++) {
            g.addEdge(i, i + 1);
        }
        g.addEdge(19, 19);
        System.out.println("strict graph {");
        g.neighbors
                .keySet()
                .stream()
                .forEach(
                        i -> {
                            Stream.of(g.neighbors.get(i))
                                    .flatMap(j -> j.stream())
                                    .forEach(
                                            k -> System.out.println(i + "--"
                                                    + k + ";"));
                        });
        // change the start point here
        g.dfsHasCircle(15);
        
        Set<Pair> uniqueCircle = new HashSet<>();
        g.circles
        .keySet()
        .stream()
        .forEach(
                i -> {
                    Stream.of(g.circles.get(i))
                            .flatMap(j -> j.stream())
                            .forEach(k -> uniqueCircle.add(g.new Pair(i, k)));
                });
        uniqueCircle.stream().forEach(i -> {
            g.printCircle(i.a, i.b);
        });
        System.out.println("//"+uniqueCircle);
        
        System.out.println("}");
        System.out.println("number of points: " + g.size());
        System.out.println("number of edges: " + g.edgeSize());
        System.out.println("can we reach point 6 from 3: "
                + g.marked.contains(6));
        System.out.println("can we reach point 16 from 3: "
                + g.marked.contains(16));
        System.out.println("can we reach point 19 from 3: "
                + g.marked.contains(19));
        System.out.println("is there circle: " + g.hasCircle);
        System.out.println("how many circles dected for this traversal: "
                + uniqueCircle.size());
    }
}