1 package org.codehaus.plexus.util.dag;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.LinkedList;
22 import java.util.List;
23 import java.util.Map;
24
25
26
27
28
29 public class CycleDetector
30 {
31
32 private final static Integer NOT_VISITED = 0;
33
34 private final static Integer VISITING = 1;
35
36 private final static Integer VISITED = 2;
37
38 public static List<String> hasCycle( final DAG graph )
39 {
40 final List<Vertex> vertices = graph.getVertices();
41
42 final Map<Vertex, Integer> vertexStateMap = new HashMap<>();
43
44 List<String> retValue = null;
45
46 for ( Vertex vertex : vertices )
47 {
48 if ( isNotVisited( vertex, vertexStateMap ) )
49 {
50 retValue = introducesCycle( vertex, vertexStateMap );
51
52 if ( retValue != null )
53 {
54 break;
55 }
56 }
57 }
58
59 return retValue;
60 }
61
62
63
64
65
66
67
68
69
70 public static List<String> introducesCycle( final Vertex vertex, final Map<Vertex, Integer> vertexStateMap )
71 {
72 final LinkedList<String> cycleStack = new LinkedList<>();
73
74 final boolean hasCycle = dfsVisit( vertex, cycleStack, vertexStateMap );
75
76 if ( hasCycle )
77 {
78
79
80
81
82
83
84 final String label = cycleStack.getFirst();
85
86 final int pos = cycleStack.lastIndexOf( label );
87
88 final List<String> cycle = cycleStack.subList( 0, pos + 1 );
89
90 Collections.reverse( cycle );
91
92 return cycle;
93 }
94
95 return null;
96 }
97
98 public static List<String> introducesCycle( final Vertex vertex )
99 {
100 final Map<Vertex, Integer> vertexStateMap = new HashMap<>();
101
102 return introducesCycle( vertex, vertexStateMap );
103 }
104
105 private static boolean isNotVisited( final Vertex vertex, final Map<Vertex, Integer> vertexStateMap )
106 {
107 final Integer state = vertexStateMap.get( vertex );
108
109 return ( state == null ) || NOT_VISITED.equals( state );
110 }
111
112 private static boolean isVisiting( final Vertex vertex, final Map<Vertex, Integer> vertexStateMap )
113 {
114 final Integer state = vertexStateMap.get( vertex );
115
116 return VISITING.equals( state );
117 }
118
119 private static boolean dfsVisit( final Vertex vertex, final LinkedList<String> cycle,
120 final Map<Vertex, Integer> vertexStateMap )
121 {
122 cycle.addFirst( vertex.getLabel() );
123
124 vertexStateMap.put( vertex, VISITING );
125
126 for ( Vertex v : vertex.getChildren() )
127 {
128 if ( isNotVisited( v, vertexStateMap ) )
129 {
130 final boolean hasCycle = dfsVisit( v, cycle, vertexStateMap );
131
132 if ( hasCycle )
133 {
134 return true;
135 }
136 }
137 else if ( isVisiting( v, vertexStateMap ) )
138 {
139 cycle.addFirst( v.getLabel() );
140
141 return true;
142 }
143 }
144 vertexStateMap.put( vertex, VISITED );
145
146 cycle.removeFirst();
147
148 return false;
149 }
150
151 }