CS(Computer Science)/Algorithm

다익스트라 알고리즘(Dijkstra)

환성 2023. 1. 7. 17:18
728x90

다익스트라 알고리즘

그래프에서 꼭짓점 간의 최단 경로를 찾는 알고리즘

가중치가 음수를 가지면 안되고 인접한 정점으로 가는 간선중 가장 적은 비용을 가지는 간선을 택한다. 알고리즘 수행중 새로운 경로가 생기면 그 경로를 기록하고 이후에 생기는 또 다른 경로와 비교하면서 최단 경로를 탐색한다.

 

 

다익스트라 알고리즘 순서

 

1. 최단 거리 값은 무한대 값으로 초기화한다.

for(int i = 1; i <= n; i++){
    distance[i] = Integer.MAX_VALUE;
}

2. 시작 정점의 최단 거리는 0이다. 그리고 시작 정점을 방문 처리한다.

distance[start] = 0;
visited[start] = true;

3. 시작 정점과 연결된 정점들의 최단 거리 값을 갱신한다.

for(int i = 1; i <= n; i++){
    if(!visited[i] && map[start][i] != 0) {
    	distance[i] = map[start][i];
    }
}

 

4. 방문하지 않은 정점 중 최단 거리가 최소인 정점을 찾는다.

int min = Integer.MAX_VALUE;
int midx = -1;

for(int i = 1; i <= n; i++){
    if(!visited[i] && distance[i] != Integer.MAX_VALUE) {
    	if(distance[i] < min) {
            min = distance[i];
            midx = i;
        }
    }
}

5. 찾은 정점을 방문 체크로 변경 후, 해당 정점과 연결된 방문하지 않은 정점의 최단 거리 값을 갱신한다.

visited[midx] = true;
for(int i = 1; i <= n; i++){
    if(!visited[i] && map[midx][i] != 0) {
    	if(distance[i] > distance[midx] + map[midx][i]) {
            distance[i] = distance[midx] + map[midx][i];
        }
    }
}

 

6. 모든 정점을 방문할 때까지 4~5번을 반복한다.

 

다익스트라 인접 행렬로 구현한 코드

public class Dijkstra {

	public static void main(String[] args) {
        Graph g = new Graph(6); // 노드 수 만큼 그래프 생성
        
        // 시작, 끝, 간선 가중치 입력
        g.input(0, 1, 7);
        g.input(0, 2, 9);
        g.input(0, 5, 14);
        g.input(1, 2, 10);
        g.input(1, 3, 15);
        g.input(2, 3, 11);
        g.input(2, 5, 2);
        g.input(3, 4, 6);
        g.input(4, 5, 9);
        
        // 시작노드 기준 다익스트라 알고리즘 실행
        g.dijkstra(0);
	}
}

class Graph{
    private int n;           // 노드들의 수
    private int maps[][];    // 노드들간의 가중치 저장할 변수
 
    public Graph(int n){
        this.n = n;
        maps = new int[n][n];
        
        // 인접행렬 모든 값 무한대로 초기화
        for(int i=0; i<n; ++i){
        	for(int j=0; j<n; ++j){
        		maps[i][j] = Integer.MAX_VALUE;
        	}
        }
    }
    
    public void input(int i,int j,int w){
        maps[i][j] = w;
        maps[j][i] = w;
    }
 
    public void dijkstra(int v){
        int distance[] = new int[n];          // 최단 거리를 저장할 변수
        boolean[] check = new boolean[n];     // 해당 노드를 방문했는지 체크할 변수
         
        // distance값 초기화. 무한대를 int 자료형의 최대값으로 표현했다.
        for(int i=0; i<n; ++i){
            distance[i] = Integer.MAX_VALUE;
        }
         
        // 시작노드값 초기화.
        distance[v] = 0;
        check[v] = true;
        
        // 결과값 출력
        for(int i=0; i<n; ++i){
        	if(distance[i] == 2147483647) System.out.print("∞ ");
        	else System.out.print(distance[i]+" ");
        }
        System.out.println("");
         
        // 연결노드 distance갱신
        for(int i=0; i<n; ++i){
            if(!check[i] && maps[v][i] != Integer.MAX_VALUE){
                distance[i] = maps[v][i];
            }
        }
        
        // 결과값 출력
        for(int i=0; i<n; ++i){
        	if(distance[i] == 2147483647) System.out.print("∞ ");
        	else System.out.print(distance[i]+" ");
        }
        System.out.println("");
         
        for(int a=0; a<n-1; ++a){
            // 원래는 모든 노드가 true될때까지 인데
            // 노드가 n개 있을 때 다익스트라를 위해서 반복수는 n-1번이면 된다.
            // 원하지 않으면 각각의 노드가 모두 true인지 확인하는 식으로 구현해도 된다.
            int min = Integer.MAX_VALUE;
            int min_index = -1;
            
            // 노드 최소값 찾기
            for(int i=0; i<n; ++i){
                if(!check[i]){
                    if(distance[i] < min){
                        min = distance[i];
                        min_index = i;
                    }
                }
            }
            
            // 다른 노드를 거쳐서 가는 것이 더 비용이 적은지 확인한다.
            check[min_index] = true;
            for(int i=0; i<n; ++i){
                if(!check[i] && maps[min_index][i] != Integer.MAX_VALUE){
                    if(distance[min_index] + maps[min_index][i] < distance[i]){
                        distance[i] = distance[min_index] + maps[min_index][i];
                    }
                }
            }
            
            // 결과값 출력
            for(int i=0; i<n; ++i){
            	if(distance[i] == 2147483647) System.out.print("∞ ");
            	else System.out.print(distance[i]+" ");
            }
            System.out.println("");
        }
    }

 

다익스트라 적용 시 알아아할 점

  • 인접 행렬로 구현 시  시간 복잡도는 O(n²)이다.
  • 인접 리스트로 구현 시 시간 복잡도는 O(nlogn)이다.
  • 선형 탐색으로 시간 초과가 날 시 인접 리스트로 접근해야한다(우선순위 큐)
  • 간선의 값이 양수일 때만 가능하다. 

 

 

실생활 응용

  • 가능한 적은 비용으로 가장 빠르게 해답에 도달하는 경로를 찾아내는 대부분 문제에 해당된다.
  • 내비게이션, 미로탐색 알고리즘, 최소 운송비 지점 구하기, 가장 빠른 길 찾기 등에 이용된다.

 

 

 

 

 

 

 

 

출처:

https://gyoogle.dev/blog/algorithm/Dijkstra.html

'CS(Computer Science) > Algorithm' 카테고리의 다른 글

이진 탐색  (0) 2023.01.12
병합 정렬  (0) 2023.01.12
퀵 정렬  (0) 2023.01.04
삽입 정렬  (0) 2023.01.04
선택 정렬  (0) 2023.01.04