|
| 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 | +} |
0 commit comments