-
Notifications
You must be signed in to change notification settings - Fork 53
Expand file tree
/
Copy pathBeanGraph.java
More file actions
138 lines (114 loc) · 4.4 KB
/
Copy pathBeanGraph.java
File metadata and controls
138 lines (114 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package arhangel.dim.container;
import arhangel.dim.container.exceptions.CycleReferenceException;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import static java.util.Collections.reverse;
/**
*
*/
public class BeanGraph {
// Граф представлен в виде списка связности для каждой вершины
private Map<BeanVertex, List<BeanVertex>> vertices = new HashMap<>();
private Map<String, BeanVertex> vertexByName = new HashMap<>();
/**
* Добавить вершину в граф
* @param value - объект, привязанный к вершине
*/
public BeanVertex addVertex(Bean value) {
BeanVertex newVertex = new BeanVertex(value);
vertices.put(newVertex, new ArrayList<BeanVertex>());
vertexByName.put(value.getName(), newVertex);
return newVertex;
}
/**
* Соединить вершины ребром
* @param from из какой вершины
* @param to в какую вершину
*/
public void addEdge(BeanVertex from ,BeanVertex to) {
List<BeanVertex> incidentVertices = vertices.get(from);
incidentVertices.add(to);
}
public BeanGraph() {}
public BeanGraph(List<Bean> beans) {
// adding all the vertices
for (Bean bean : beans) {
addVertex(bean);
}
// adding edges between vertices
for (Bean bean : beans) {
BeanVertex from = vertexByName.get(bean.getName());
HashMap<String, Property> properties = (HashMap<String, Property>) bean.getProperties();
for (Property property : properties.values()) {
if (property.getType() == ValueType.VAL) {
continue;
}
BeanVertex to = vertexByName.get(property.getName());
addEdge(from, to);
}
}
}
/**
* Проверяем, связаны ли вершины
*/
public boolean isConnected(BeanVertex v1, BeanVertex v2) {
List<BeanVertex> incidentVertices = vertices.get(v1);
return incidentVertices.contains(v2);
}
/**
* Получить список вершин, с которыми связана vertex
*/
public List<BeanVertex> getLinked(BeanVertex vertex) {
return vertices.get(vertex);
}
/**
* Количество вершин в графе
*/
public int size() {
return vertices.size();
}
private enum VertexType {
NOT_PROCESSED, // dfs в вершину еще не заходил
STARTED_PROCESSING, // dfs зашел в вершину
FINISHED_PROCESSING // dfs вышел из вершины
}
/**
* Проверить граф на наличие циклов
*/
private boolean isCircle(BeanVertex vertex, List<BeanVertex> sortedVertices,
Map<BeanVertex, VertexType> usedVertices) {
usedVertices.put(vertex, VertexType.STARTED_PROCESSING);
for (BeanVertex incidentVertex : vertices.get(vertex)) {
if (usedVertices.get(incidentVertex).equals(VertexType.NOT_PROCESSED)) {
isCircle(incidentVertex, sortedVertices, usedVertices);
} else if (usedVertices.get(incidentVertex).equals(VertexType.STARTED_PROCESSING)) {
return true;
}
}
sortedVertices.add(vertex);
usedVertices.put(vertex, VertexType.FINISHED_PROCESSING);
return false;
}
/**
* Отсортировать вершины графа в топологическом порядке
*/
public List<BeanVertex> sortTopologically() throws CycleReferenceException {
Map<BeanVertex, VertexType> usedVertices = new HashMap<>();
for (BeanVertex vertex : vertices.keySet()) {
usedVertices.put(vertex, VertexType.NOT_PROCESSED);
}
List<BeanVertex> sortedVertices = new ArrayList<>();
for (BeanVertex vertex : vertices.keySet()) {
if (!usedVertices.get(vertex).equals(0)) {
continue;
}
boolean foundCircle = isCircle(vertex, sortedVertices, usedVertices);
if (foundCircle) {
throw new CycleReferenceException("circle reference found");
}
}
return sortedVertices;
}
}