record logo record

다익스트라 알고리즘(Dijkstra Algorithm) 이란?

다익스트라 알고리즘(Dijkstra Algorithm)의 특징

다익스트라 알고리즘(Dijkstra Algorithm)의 알고리즘 예시

  1. 출발 노드를 설정한다.
  2. 출발 노드를 기준으로 각 노드의 최소 비용을 저장한다.
  3. 방문하지 않은 노드 중에서 가장 비용이 적은 노드를 선택한다.
  4. 해당 노드를 거쳐서 특정한 노드로 가는 경우를 고려하여 최소 비용을 갱신한다.
  5. 3 ~ 4 과정을 반복한다.

다음과 같은 그래프는 실제로 컴퓨터 안에서 처리할 때 이차원 배열 형태로 처리해야 한다.

위의 표를 보면 1행 2열의 값이 3인것을 알 수 있다. 이는 위의 그래프에서 노드1에서 노드2로 가는 비용을 의미한다.

2번 노드를 선택했을 때 2번 노드에서 5번 노드로 가는 비용이 이전 값인 무한대 보다 작기 때문에 7로 갱신됨을 알 수 있다.
그리고 가장 작은 비용인 3(4번 노드)을 선택한다.

4번 노드를 선택했을때 3번 노드로 가는 비용이 이전에 1번 노드에서 3번 노드로 가는 비용보다 4번 노드를 거쳐서 가는 비용이 더 적기 때문에 4로 갱신해준다.
또한 5번 노드로 가는 비용 또한 4번 노드를 거쳐가는 것이 Step2에서 2번 노드를 선택했을때 갱신했던 비용보다 더 적기 때문에 새롭게 갱신해준다.

선형 탐색을 이용한 다익스트라 알고리즘(Dijkstra Algorithm) 구현

#include <stdio.h>

int num = 6;
// 무한을 표현하려고 선언 
int INF = 1000000000;

// 전체 그래프 초기화 
int a[6][6] = {
	{0, 2, 5, 1, INF, INF},
	{2, 2, 5, 1, INF, INF},
	{5, 3, 0, 3, 1, 5},
	{1, 2, 3, 0, 1, INF},
	{INF, INF, 1, 1, 0, 2},
	{INF, INF, 5, INF, 2, 0},
};
 
bool v[6]; // 방문한 노드인지 확인 배열 
int d[6];  // 최단거리   

// 가장 최소 거리를 가지는 정점을 반환한다. 
// 시간 복잡도 O(N)
int getSmallIndex(){
	int min = INF;
	int index = 0;
	
	for(int i = 0; i < num; i++) {
		if(d[i] < min && !v[i]){
			min = d[i];
			index = i;
		}
	}
	
	return index;
}
void dijkstra(int start){
	for(int i = 0; i < num; i++){
		d[i] = a[start][i];
		
	}
	
	v[start] = true;
	for(int i =0; i < num - 2; i++){
		int current = getSmallIndex();
		v[current] = true;
        // 시간 복잡도 O(N)
		for(int j = 0; j < 6; j++){
			// 방문하지 않았다면 
			if(!v[j]){
				// 현재 보고있는 노드의 최소비용에서 해당 노드를 거처서 그 노드의 인접한 노드로 가는 비용을 더한 값
				//  현재 인접한 노드로 가는 최소 비용보다 더 작다면 갱신해준다. 
				if( d[current] + a[current][j] < d[j] ) {
					d[j] = d[current] + a[current][j];
				}
			}	
		}
	}
}
 
int main(void) {
	
	dijkstra(0);
	
	for(int i = 0; i < num; i++) {
		printf("%d ", d[i]);
	} 
	return 0;
}

인접 리스트 방식을 이용한 다익스트라 알고리즘(Dijkstra Algorithm) 구현

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int num = 6;
// 무한을 표현하려고 선언 
int INF = 1000000000;



vector<pair<int, int> > a[7]; // 간선 정보 
int d[7];  // 최단거리 (최소 비용)

void dijkstra(int start){
	d[start] = 0;
	// priority_queue는 기본적으로 더 큰값을 기준으로 최상단 노드를 만든다. (최대 힙)
	priority_queue<pair<int, int> > pq; // 힙 구조 입니다.
	pq.push(make_pair(start, 0));
	// 가까운 순서대로 처리하므로 큐를 사용한다.
	// priority_queue 가 비어있지 않다면 하나씩 꺼낸다. 
	while(!pq.empty()) {
		int current = pq.top().first;
		// priority_queue가 최대힙 구조로 형성이 되기때문에 
		// 짧은 것이 먼저 오도록 음수화(-) 한다.
		int distance = -pq.top().second;
		pq.pop();
		// 최단 거리가 아닌 경우 스킵
		if(d[current] < distance) continue;
		for(int i = 0; i < a[current].size(); i++) {
			// 선택된 노드의 인접 노드
			int next = a[current][i].first;
			// 선택된 노드 거쳐서 인접 노드로 가는 비용
			int nextDistance = distance + a[current][i].second;
			// 기존의 최소 비용보다 더 저렴하다면 교체한다.
			if(nextDistance < d[next]) {
				d[next] = nextDistance;
				// nextDistance를 음수로 저장하는 이유 힙이 최대 힙 구조로 형성되기 때문이다.
				// 더 작은 값이 윗 쪽으로 가게 만들기 위해서이다. 
				pq.push(make_pair(next, -nextDistance));
			}
		}
	}
}
 
int main(void) {
	// 연결되지 않은 경우 비용은 무한
	for(int i = 1; i <= num; i++) {
		d[i] = INF; 
	} 
	
	a[1].push_back(make_pair(2, 2));
	a[1].push_back(make_pair(3, 5));
	a[1].push_back(make_pair(4, 1));
	
	a[2].push_back(make_pair(1, 2));
	a[2].push_back(make_pair(3, 3));
	a[2].push_back(make_pair(4, 2));
	
	
	a[3].push_back(make_pair(1, 5));
	a[3].push_back(make_pair(2, 3));
	a[3].push_back(make_pair(4, 3));
	a[3].push_back(make_pair(5, 1));
	a[3].push_back(make_pair(6, 5));
	
	a[4].push_back(make_pair(1, 1));
	a[4].push_back(make_pair(2, 2));
	a[4].push_back(make_pair(3, 3));
	a[4].push_back(make_pair(5, 1));
	
	a[5].push_back(make_pair(3, 1));
	a[5].push_back(make_pair(4, 1));
	a[5].push_back(make_pair(6, 2));
	
	a[6].push_back(make_pair(3, 5));
	a[6].push_back(make_pair(5, 2));
	
	
	dijkstra(1);
	
	// 결과 출력 
	for(int i = 1; i <= num; i++) {
		printf("%d ", d[i]);
	} 
	return 0;
} 

다익스트라 구현(java)

import java.util.HashMap;
import java.util.*;

class Destination implements Comparable<Destination> {
	String destination;
	int distance;
	int time;

	Destination(String destination, int distance, int time) {
		this.destination = destination;
		this.distance = distance;
		this.time = time;
	}

	@Override
	public int compareTo(Destination o) {
		return this.distance <= o.distance ? 1 : -1;
	}
}

public class Dijkstra {
	static String[] initVertex = {"교대역","강남역","남부터미널역",
				"양재역","매봉역","역삼역","양재시민의숲역"};
	static Map<String, List<Destination> > map = new HashMap<>();
	static Map<String, Integer> check = new HashMap<>();
	
	public static void dijkstra(String start, String end) {
		PriorityQueue<Destination> pq = new PriorityQueue<>();
		pq.add(new Destination(start, 0, 0));
		while (!pq.isEmpty()) {
			Destination cur = pq.poll();
			String curPosition = cur.destination;
			int curDist = -cur.distance;
			int curTime = cur.time;

			if (curPosition == end) {
				System.out.println("거리: "+curDist+"km\n시간: "+curTime+"초");
				return;
			}
			if (!map.containsKey(curPosition)) continue;
			if (check.get(curPosition) < curDist) continue;
			for (int i = 0; i < map.get(curPosition).size(); i++) {
				Destination next = map.get(curPosition).get(i);
				String nextPosition = next.destination;
				int nextDist = curDist + next.distance;
				int nextTime = curTime + next.time;
				if (check.get(nextPosition) > nextDist) {
					check.put(nextPosition, nextDist);
					pq.add(new Destination(nextPosition, -nextDist, nextTime));
				}
			}
		}
	}

	public static void init() {
		map.computeIfAbsent("교대역", V->new ArrayList<>()).add(new Destination("강남역", 2, 3));
		map.computeIfAbsent("강남역", V->new ArrayList<>()).add(new Destination("역삼역", 2, 3));
		map.computeIfAbsent("교대역", V->new ArrayList<>()).add(new Destination("남부터미널역", 3, 2));
		map.computeIfAbsent("남부터미널역", V->new ArrayList<>()).add(new Destination("양재역", 6, 5));
		map.computeIfAbsent("양재역", V->new ArrayList<>()).add(new Destination("매봉역", 1, 1));
		map.computeIfAbsent("강남역", V->new ArrayList<>()).add(new Destination("양재역", 2, 8));
		map.computeIfAbsent("양재역", V->new ArrayList<>()).add(new Destination("양재시민의숲역", 10, 3));
		for (String vertex : initVertex) {
			check.put(vertex, 9999);
		}
	}

	public static void main(String[] args) {
		init();
		dijkstra("교대역", "양재역");
	}
}

References