package com.jwetherell.algorithms.graph; import java.util.HashSet; import java.util.List; import java.util.Set; import com.jwetherell.algorithms.data_structures.Graph; /** * Cycle detection in an undirected graph using depth first search. * * @author Justin Wetherell */ public class CycleDetection { private CycleDetection() { } /** * Cycle detection on a unidrected graph. * * @param graph Graph * @return true if a cycle exists */ public static boolean detect(Graph graph) { if (graph == null) throw new IllegalArgumentException("Graph is NULL."); if (graph.getType() != Graph.TYPE.UNDIRECTED) throw new IllegalArgumentException("Graph is needs to be Undirected."); final Set> visitedVerticies = new HashSet>(); final Set> visitedEdges = new HashSet>(); final List> verticies = graph.getVertices(); if (verticies == null || verticies.size() == 0) return false; // Select the zero-ith element as the root final Graph.Vertex root = verticies.get(0); return depthFirstSearch(root, visitedVerticies, visitedEdges); } private static final boolean depthFirstSearch(Graph.Vertex vertex, Set> visitedVerticies, Set> visitedEdges) { if (!visitedVerticies.contains(vertex)) { // Found an unvisited, add to the set visitedVerticies.add(vertex); final List> edges = vertex.getEdges(); if (edges != null) { // Follow each unvisited edge, visit the vertex the edge connects to. for (Graph.Edge edge : edges) { final Graph.Vertex to = edge.getToVertex(); boolean result = false; if (to != null && !visitedEdges.contains(edge)) { visitedEdges.add(edge); final Graph.Edge recip = new Graph.Edge(edge.getCost(), edge.getToVertex(), edge.getFromVertex()); visitedEdges.add(recip); result = depthFirstSearch(to, visitedVerticies, visitedEdges); } if (result == true) return result; } } } else { // visited return true; } return false; } }