Skip to content

Commit 53192e2

Browse files
authoredSep 2, 2020
Merge pull request #48 from Data-Structure-Study/yoonexample
크루스칼 알고리즘 구현(끝)
2 parents 876f64a + dcfabc5 commit 53192e2

File tree

8 files changed

+391
-1
lines changed

8 files changed

+391
-1
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
package graph;
2+
3+
import java.util.Comparator;
4+
import java.util.StringJoiner;
5+
import list.DummyDoublyLinkedList;
6+
import list.List;
7+
import priorityqueue.HeapPriorityQueue;
8+
import priorityqueue.PriorityQueue;
9+
import queue.LinkedListQueue;
10+
import queue.Queue;
11+
import stack.ListStack;
12+
import stack.Stack;
13+
14+
public class ListWeightGraph implements WeightedGraph {
15+
16+
private final List<Enum<?>>[] vertices;
17+
private final PriorityQueue<WeightEdge> edgePriorityQueue;
18+
19+
public ListWeightGraph(int vertexCount, Class<? extends Enum<?>> clazz) {
20+
edgePriorityQueue = new HeapPriorityQueue<>(Comparator.comparingInt(o -> o.weight));
21+
Enum<?>[] enumConstants = clazz.getEnumConstants();
22+
int min = Math.min(vertexCount, enumConstants.length);
23+
24+
this.vertices = new List[min];
25+
for (int i = 0; i < min; i++) {
26+
this.vertices[i] = new DummyDoublyLinkedList<>();
27+
this.vertices[i].insert(enumConstants[i]);
28+
}
29+
}
30+
31+
@Override
32+
public void addEdge(Enum<?> fromV, Enum<?> toV, int weight) {
33+
WeightEdge edge = new WeightEdge(weight, fromV, toV);
34+
vertices[fromV.ordinal()].insert(toV);
35+
vertices[toV.ordinal()].insert(fromV);
36+
37+
edgePriorityQueue.enqueue(edge);
38+
}
39+
40+
@Override
41+
public String showGraphEdgeWeightInfo() {
42+
List<WeightEdge> weightEdgeList = new DummyDoublyLinkedList<>();
43+
StringBuilder sb = new StringBuilder();
44+
45+
while (!this.edgePriorityQueue.isEmpty()) {
46+
WeightEdge edge = this.edgePriorityQueue.dequeue();
47+
weightEdgeList.insert(edge);
48+
sb.append(edge.showEdgeInfo()).append("\n");
49+
}
50+
51+
for (int i = 0; i < weightEdgeList.size(); i++) {
52+
this.edgePriorityQueue.enqueue(weightEdgeList.get(i));
53+
}
54+
55+
return sb.toString();
56+
}
57+
58+
@Override
59+
public void convertToMST() {
60+
int vertexCount = this.vertices.length;
61+
int edgeCount = this.edgePriorityQueue.size() + 1;
62+
List<WeightEdge> edges = new DummyDoublyLinkedList<>();
63+
64+
// MST가 될 때까지 while문을 반복
65+
while (edgeCount != vertexCount) {
66+
WeightEdge edge = this.edgePriorityQueue.dequeue();
67+
removeEdge(edge.fromVertex, edge.toVertex); // 그래프에서 제거해본다.
68+
edgeCount--;
69+
70+
if (!isConnectedWith(edge.fromVertex, edge.toVertex)) { // 연결되어 있지 않으면 복구
71+
recoverEdge(edge);
72+
edges.insert(edge);
73+
edgeCount++;
74+
}
75+
}
76+
77+
// 간선 정보 복원
78+
for (int i = 0; i < edges.size(); i++) {
79+
this.edgePriorityQueue.enqueue(edges.get(i));
80+
}
81+
}
82+
83+
private boolean isConnectedWith(Enum<?> fromVertex, Enum<?> toVertex) {
84+
boolean[] visited = new boolean[vertices.length];
85+
Stack<Enum<?>> vertexStack = new ListStack<>();
86+
vertexStack.push(fromVertex);
87+
88+
while (!vertexStack.isEmpty()) {
89+
Enum<?> visitV = vertexStack.pop();
90+
if (visitVertex(visited, visitV)) {
91+
if (visitV.equals(toVertex)) {
92+
return true;
93+
}
94+
}
95+
96+
List<Enum<?>> vertexList = vertices[visitV.ordinal()];
97+
for (int i = 0; i < vertexList.size(); i++) {
98+
Enum<?> vertex = vertexList.get(i);
99+
if (!visited[vertex.ordinal()]) {
100+
vertexStack.push(vertex);
101+
}
102+
}
103+
}
104+
105+
return false;
106+
}
107+
108+
private void recoverEdge(WeightEdge edge) {
109+
vertices[edge.fromVertex.ordinal()].insert(edge.toVertex);
110+
vertices[edge.toVertex.ordinal()].insert(edge.fromVertex);
111+
}
112+
113+
private void removeEdge(Enum<?> fromVertex, Enum<?> toVertex) {
114+
removeVertexFromLink(fromVertex, toVertex);
115+
removeVertexFromLink(toVertex, fromVertex);
116+
}
117+
118+
private void removeVertexFromLink(Enum<?> vertexA, Enum<?> vertexB) {
119+
List<Enum<?>> vertexLinkInfo = this.vertices[vertexA.ordinal()];
120+
for (int i = 0; i < vertexLinkInfo.size(); i++) {
121+
if (vertexLinkInfo.get(i).equals(vertexB)) {
122+
vertexLinkInfo.remove(i);
123+
return;
124+
}
125+
}
126+
throw new IllegalArgumentException("해당 정점들은 연결되어있지 않습니다.");
127+
}
128+
129+
@Override
130+
public void addEdge(Enum<?> fromV, Enum<?> toV) {
131+
throw new UnsupportedOperationException("이 메소드는 지원하지 않습니다.");
132+
}
133+
134+
@Override
135+
public String showGraphEdgeInfo() {
136+
StringBuilder sb = new StringBuilder();
137+
138+
for (List<Enum<?>> vertex : vertices) {
139+
if (vertex.size() > 1) {
140+
for (int i = 0; i < vertex.size(); i++) {
141+
sb.append(vertex.get(i));
142+
if (i == 0) {
143+
sb.append(": ");
144+
} else if (i < vertex.size() - 1) {
145+
sb.append(" ");
146+
}
147+
}
148+
sb.append("\n");
149+
}
150+
}
151+
152+
return sb.toString();
153+
}
154+
155+
@Override
156+
public String depthFirstSearch(Enum<?> startV) {
157+
boolean[] visited = new boolean[vertices.length];
158+
StringJoiner sj = new StringJoiner(" ");
159+
Stack<Enum<?>> vertexStack = new ListStack<>();
160+
vertexStack.push(startV);
161+
162+
while (!vertexStack.isEmpty()) {
163+
Enum<?> visitV = vertexStack.pop();
164+
165+
if (visitVertex(visited, visitV)) {
166+
sj.add(visitV.toString());
167+
}
168+
List<Enum<?>> vertexList = vertices[visitV.ordinal()];
169+
for (int i = 0; i < vertexList.size(); i++) {
170+
Enum<?> vertex = vertexList.get(i);
171+
if (!visited[vertex.ordinal()]) {
172+
vertexStack.push(vertex);
173+
}
174+
}
175+
}
176+
177+
return sj.toString();
178+
}
179+
180+
@Override
181+
public String breadthFirstSearch(Enum<?> startV) {
182+
boolean[] visited = new boolean[vertices.length];
183+
StringJoiner sj = new StringJoiner(" ");
184+
Queue<Enum<?>> vertexQueue = new LinkedListQueue<>();
185+
vertexQueue.enqueue(startV);
186+
187+
while (!vertexQueue.isEmpty()) {
188+
Enum<?> visitV = vertexQueue.dequeue();
189+
190+
if (visitVertex(visited, visitV)) {
191+
sj.add(visitV.toString());
192+
}
193+
194+
List<Enum<?>> vertexList = vertices[visitV.ordinal()];
195+
for (int i = 0; i < vertexList.size(); i++) {
196+
Enum<?> vertex = vertexList.get(i);
197+
if (!visited[vertex.ordinal()]) {
198+
vertexQueue.enqueue(vertex);
199+
}
200+
}
201+
}
202+
203+
return sj.toString();
204+
}
205+
206+
private boolean visitVertex(boolean[] visited, Enum<?> vertex) {
207+
if (visited[vertex.ordinal()]) {
208+
return false;
209+
}
210+
visited[vertex.ordinal()] = true;
211+
return true;
212+
}
213+
214+
private static class WeightEdge {
215+
216+
private final int weight;
217+
private final Enum<?> fromVertex;
218+
private final Enum<?> toVertex;
219+
220+
public WeightEdge(int weight, Enum<?> fromVertex, Enum<?> toVertex) {
221+
this.weight = weight;
222+
this.fromVertex = fromVertex;
223+
this.toVertex = toVertex;
224+
}
225+
226+
private String showEdgeInfo() {
227+
return "(" + fromVertex.toString() + "-" + toVertex.toString() + "), " + "w: " + weight;
228+
}
229+
}
230+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package graph;
2+
3+
/**
4+
* 가중치 그래프의 인터페이스
5+
*
6+
* @author dion
7+
*/
8+
public interface WeightedGraph extends Graph {
9+
10+
/**
11+
* 매개변수 fromV와 toV로 전달된 정점을 연결하는 간선에 가중치를 부여하여 그래프에 추가합니다.
12+
*
13+
* @param fromV 시작하는 정점
14+
* @param toV 도달하는 정점
15+
* @param weight 간선의 가중치
16+
*/
17+
void addEdge(Enum<?> fromV, Enum<?> toV, int weight);
18+
19+
/**
20+
* 그래프의 간선정보 및 가중치를 반환합니다.
21+
*
22+
* @return 그래프의 간선정보 및 가중치
23+
*/
24+
String showGraphEdgeWeightInfo();
25+
26+
/**
27+
* 크루스칼 알고리즘을 이용해 최소신장 트리로 변환합니다.
28+
*/
29+
void convertToMST();
30+
}

‎yoonexample/src/main/java/heap/ArrayUsefulHeap.java

+5
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ public E delete() {
6464
return retData;
6565
}
6666

67+
@Override
68+
public int size() {
69+
return this.numOfData;
70+
}
71+
6772
/**
6873
* 부모 노드의 인덱스 반환 요청
6974
*

‎yoonexample/src/main/java/heap/UsefulHeap.java

+7
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@ public interface UsefulHeap<E> {
2727
* @return 힙에 저장되어 있던 최우선순위 데이터
2828
*/
2929
E delete();
30+
31+
/**
32+
* 힙에 저장되어 있는 데이터의 수를 반환합니다.
33+
*
34+
* @return 힙에 저장되어 있는 데이터의 수
35+
*/
36+
int size();
3037
}

‎yoonexample/src/main/java/priorityqueue/HeapPriorityQueue.java

+5
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,9 @@ public E dequeue() {
3030
}
3131
return this.heap.delete();
3232
}
33+
34+
@Override
35+
public int size() {
36+
return this.heap.size();
37+
}
3338
}

‎yoonexample/src/main/java/priorityqueue/PriorityQueue.java

+7
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@ public interface PriorityQueue<E> {
2727
* @return 우선순위가 가장 높은 데이터
2828
*/
2929
E dequeue();
30+
31+
/**
32+
* 우선순위 큐에 저장되어 있는 데이터의 수를 반환합니다.
33+
*
34+
* @return 우선순위 큐에 저장되어 있는 데이터의 수
35+
*/
36+
int size();
3037
}

‎yoonexample/src/test/java/graph/GraphTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ void setUp() {
2020
}
2121

2222
@Test
23-
void 방향_그래프_정점_연결_테스트() {
23+
void 무방향_그래프_정점_연결_테스트() {
2424
graph.addEdge(Point.A, Point.B);
2525
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: B\nB: A\n");
2626

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package graph;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5+
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
9+
class WeightedGraphTest {
10+
11+
WeightedGraph graph;
12+
13+
@BeforeEach
14+
void setUp() {
15+
this.graph = new ListWeightGraph(6, Point.class);
16+
}
17+
18+
@Test
19+
void 가중치_그래프_초기화_테스트() {
20+
assertThat(this.graph).isNotNull();
21+
}
22+
23+
@Test
24+
void 가중치_없이_생성하면_UnsupportedOperationException_발생_테스트() {
25+
assertThatThrownBy(() -> graph.addEdge(Point.A, Point.B))
26+
.isInstanceOf(UnsupportedOperationException.class);
27+
}
28+
29+
@Test
30+
void 가중치_그래프_정점_연결_테스트() {
31+
graph.addEdge(Point.A, Point.B, 9);
32+
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: B\nB: A\n");
33+
assertThat(graph.showGraphEdgeWeightInfo()).isEqualTo("(A-B), w: 9\n");
34+
35+
graph.addEdge(Point.B, Point.C, 2);
36+
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: B\nB: A C\nC: B\n");
37+
assertThat(graph.showGraphEdgeWeightInfo()).isEqualTo("(A-B), w: 9\n(B-C), w: 2\n");
38+
39+
graph.addEdge(Point.A, Point.C, 12);
40+
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: B C\nB: A C\nC: B A\n");
41+
assertThat(graph.showGraphEdgeWeightInfo())
42+
.isEqualTo("(A-C), w: 12\n(A-B), w: 9\n(B-C), w: 2\n");
43+
44+
graph.addEdge(Point.A, Point.D, 8);
45+
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: B C D\nB: A C\nC: B A\nD: A\n");
46+
assertThat(graph.showGraphEdgeWeightInfo())
47+
.isEqualTo("(A-C), w: 12\n(A-B), w: 9\n(A-D), w: 8\n(B-C), w: 2\n");
48+
49+
graph.addEdge(Point.D, Point.C, 6);
50+
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: B C D\nB: A C\nC: B A D\nD: A C\n");
51+
assertThat(graph.showGraphEdgeWeightInfo())
52+
.isEqualTo("(A-C), w: 12\n(A-B), w: 9\n(A-D), w: 8\n(D-C), w: 6\n(B-C), w: 2\n");
53+
54+
graph.addEdge(Point.A, Point.F, 11);
55+
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: B C D F\nB: A C\nC: B A D\nD: A C\nF: A\n");
56+
assertThat(graph.showGraphEdgeWeightInfo()).isEqualTo(
57+
"(A-C), w: 12\n(A-F), w: 11\n(A-B), w: 9\n(A-D), w: 8\n(D-C), w: 6\n(B-C), w: 2\n");
58+
59+
graph.addEdge(Point.F, Point.D, 4);
60+
assertThat(graph.showGraphEdgeInfo())
61+
.isEqualTo("A: B C D F\nB: A C\nC: B A D\nD: A C F\nF: A D\n");
62+
assertThat(graph.showGraphEdgeWeightInfo()).isEqualTo(
63+
"(A-C), w: 12\n(A-F), w: 11\n(A-B), w: 9\n(A-D), w: 8\n(D-C), w: 6\n(F-D), w: 4\n(B-C), w: 2\n");
64+
65+
graph.addEdge(Point.D, Point.E, 3);
66+
assertThat(graph.showGraphEdgeInfo())
67+
.isEqualTo("A: B C D F\nB: A C\nC: B A D\nD: A C F E\nE: D\nF: A D\n");
68+
assertThat(graph.showGraphEdgeWeightInfo()).isEqualTo(
69+
"(A-C), w: 12\n(A-F), w: 11\n(A-B), w: 9\n(A-D), w: 8\n(D-C), w: 6\n(F-D), w: 4\n(D-E), w: 3\n(B-C), w: 2\n");
70+
71+
graph.addEdge(Point.E, Point.C, 7);
72+
assertThat(graph.showGraphEdgeInfo())
73+
.isEqualTo("A: B C D F\nB: A C\nC: B A D E\nD: A C F E\nE: D C\nF: A D\n");
74+
assertThat(graph.showGraphEdgeWeightInfo()).isEqualTo(
75+
"(A-C), w: 12\n(A-F), w: 11\n(A-B), w: 9\n(A-D), w: 8\n(E-C), w: 7\n(D-C), w: 6\n(F-D), w: 4\n(D-E), w: 3\n(B-C), w: 2\n");
76+
77+
graph.addEdge(Point.F, Point.E, 13);
78+
assertThat(graph.showGraphEdgeInfo())
79+
.isEqualTo("A: B C D F\nB: A C\nC: B A D E\nD: A C F E\nE: D C F\nF: A D E\n");
80+
assertThat(graph.showGraphEdgeWeightInfo()).isEqualTo(
81+
"(F-E), w: 13\n(A-C), w: 12\n(A-F), w: 11\n(A-B), w: 9\n(A-D), w: 8\n(E-C), w: 7\n(D-C), w: 6\n(F-D), w: 4\n(D-E), w: 3\n(B-C), w: 2\n");
82+
}
83+
84+
@Test
85+
void 가중치_그래프_MST변환_테스트() {
86+
graph.addEdge(Point.A, Point.B, 9);
87+
graph.addEdge(Point.B, Point.C, 2);
88+
graph.addEdge(Point.A, Point.C, 12);
89+
graph.addEdge(Point.A, Point.D, 8);
90+
graph.addEdge(Point.D, Point.C, 6);
91+
graph.addEdge(Point.A, Point.F, 11);
92+
graph.addEdge(Point.F, Point.D, 4);
93+
graph.addEdge(Point.D, Point.E, 3);
94+
graph.addEdge(Point.E, Point.C, 7);
95+
graph.addEdge(Point.F, Point.E, 13);
96+
97+
graph.convertToMST();
98+
assertThat(graph.showGraphEdgeInfo()).isEqualTo("A: D\nB: C\nC: B D\nD: C F E A\nE: D\nF: D\n");
99+
assertThat(graph.showGraphEdgeWeightInfo())
100+
.isEqualTo("(A-D), w: 8\n(D-C), w: 6\n(F-D), w: 4\n(D-E), w: 3\n(B-C), w: 2\n");
101+
}
102+
103+
private enum Point {
104+
A, B, C, D, E, F, G, H, I, J
105+
}
106+
}

0 commit comments

Comments
 (0)
Please sign in to comment.