그래프를 구현하는 방법에는 인접행렬과 인접리스트가 있다. 그 중 인접리스트를 통해 그래프를 구현하려고 한다.
아래는 예시그래프와 그래프의 정점과 정점 사이의 관계를 그림으로 그려보았다.
구현하면 다음과 같다.
class Graph {
private ArrayList<ArrayList<Integer>> graphList;
public Graph(int size) {
this.graphList = new ArrayList<ArrayList<Integer>>();
for(int i=0; i<size; i++) {
this.graphList.add(new ArrayList<Integer>());
}
}
public void put(int v1, int v2) { //무방향 그래프
graphList.get(v1).add(v2);
graphList.get(v2).add(v1);
}
public ArrayList<Integer> get(int v){
return graphList.get(v);
}
}
private static Graph graph;
public static void main(String[] args) throws Exception {
//예시그래프 생성
graph = new Graph(4);
graph.put(1, 2);
graph.put(1, 3);
graph.put(1, 4);
graph.put(2, 1);
graph.put(3, 1);
graph.put(3, 4);
graph.put(4, 1);
graph.put(4, 3);
}
DFS 탐색 방법은 여러가지가 있지만 여기서는 이동할 때 부모노드를 기억하는 방식으로 탐색한다. 내가 탐색할 다음 노드가 부모노드하고 같다면 방금 지나온 길이니 넘기고 탐색을 계속하는 방식이다.
public static boolean dfs(int currentNode, int parentNode) {
for(int nextNode : graph.get(currentNode)) { //탐색 시작
if(nextNode == parentNode) { //이미 지나온 경로
continue;
}else if(dfs(nextNode, currentNode)) { //탐색 진행
return true;
}
}
return false;
}
이제 DFS탐색에서 사이클을 찾아내야 한다. 사이클을 찾아내기 위해서는 내가 방문한 노드들을 기억하고 있어야 한다. DFS 탐색이 정상적으로 진행되고 있다면, 다음노드가 부모가 아닌데 이미 한 번 방문한 노드일 경우 사이클이 발생한 것이다.
private static int[] visited; //방문했는지를 기억하기 위한 리스트 변수 추가
private static ArrayList<Integer> cyclePath; //사이클 경로 담을 변수 추가
public static boolean dfs(int currentNode, int parentNode) {
if(visited[currentNode] != -1) { //이미 방문한 노드라면 사이클 발생
//cyclePath는 지금까지의 진행경로를 전부 담고 있어서
//사이클 경로만 보기 위해서 사이클 발생 지점에서 cyclePath를 자른다.
int cyclePoint = cyclePath.indexOf(currentNode);
System.out.println("사이클 :" + cyclePath.subList(cyclePoint, cyclePath.size()));
return true;
}
visited[currentNode] = 1; //노드 방문
cyclePath.add(currentNode); //방문 노드 기록
for(int nextNode : stations.get(currentNode)) {
if(nextNode == parentNode) {
continue;
}else if(dfs(nextNode, currentNode)) {
return true;
}
}
return false;
}
그러면 전체 코드는 아래와 같이 된다.
class Graph {
private ArrayList<ArrayList<Integer>> graphList;
public Graph(int size) {
this.graphList = new ArrayList<ArrayList<Integer>>();
for(int i=0; i<size; i++) {
this.graphList.add(new ArrayList<Integer>());
}
}
public void put(int v1, int v2) { //무방향 그래프
graphList.get(v1).add(v2);
graphList.get(v2).add(v1);
}
public ArrayList<Integer> get(int v){
return graphList.get(v);
}
}
private static int[] visited;
private static ArrayList<Integer> cyclePath;
private static Graph graph;
public static void main(String[] args) throws Exception {
//예시그래프 생성
graph = new Graph(4);
graph.put(1, 2);
graph.put(1, 3);
graph.put(1, 4);
graph.put(2, 1);
graph.put(3, 1);
graph.put(3, 4);
graph.put(4, 1);
graph.put(4, 3);
//변수 초기화
visited = new int[4];
for(int i=0; i<4; i++) {
visited[i] = -1;
}
cyclePath = new ArrayList<Integer>();
dfs(1, -1);
}
public static boolean dfs(int currentNode, int parentNode) {
if(visited[currentNode] != -1) {
int cyclePoint = cyclePath.indexOf(currentNode);
System.out.println("사이클 :" + cyclePath.subList(cyclePoint, cyclePath.size()));
return true;
}
visited[currentNode] = 1;
cyclePath.add(currentNode);
for(int nextNode : stations.get(currentNode)) {
if(nextNode == parentNode) {
continue;
}else if(dfs(nextNode, currentNode)) {
return true;
}
}
return false;
}
'미역 > 자바' 카테고리의 다른 글
소수 구하기 (0) | 2021.11.05 |
---|---|
Comparable 과 Comparator (0) | 2021.11.02 |
TreeSet과 Comparator (0) | 2021.10.25 |
XOR의 성질 (0) | 2021.10.22 |
최대공약수 & 최소공배수 (0) | 2021.10.22 |