이종관
Back to Posts

다익스트라(Dijkstra) 최단 경로 알고리즘

음수 가중치 없는 그래프에서 최단 경로 찾기 - 우선순위 큐 활용 구현

2025년 1월 20일·5 min read·
algorithm
algorithm
graph
shortest-path
dijkstra
priority-queue

Dijkstra 알고리즘이란?

Dijkstra 알고리즘은 그래프에서 음의 가중치가 없는 간선들이 있을 때, 특정 시작 정점으로부터 다른 모든 정점까지의 최단 경로를 찾는 알고리즘입니다.

입력/출력

  • 입력: 정점 집합 V, 간선 집합 E (가중치 ≥ 0), 시작 정점 s
  • 출력: 시작 정점에서 모든 정점까지의 최단 거리

시간 복잡도: O(E log V) (우선순위 큐 사용)

알고리즘 아이디어

  1. 초기화: 시작 정점 거리 = 0, 나머지 = ∞
  2. 반복:
    • 우선순위 큐에서 거리가 가장 작은 정점 u를 꺼냄
    • u의 인접 정점 v에 대해 dist[u] + weight(u,v) < dist[v]이면 갱신
  3. 종료: 모든 정점 처리 완료

예시: 동작 과정

그래프 (A=0, B=1, C=2, D=3, E=4):
A --2-- B --3-- D
|       |       |
5       1       1
|       |       |
+------ C --5-- E

간선: A-B(2), A-C(5), B-C(1), B-D(3), C-D(2), D-E(1), C-E(5)
단계처리 정점dist 배열
초기-[0, ∞, ∞, ∞, ∞]
1A[0, 2, 5, ∞, ∞]
2B[0, 2, 3, 5, ∞]
3C[0, 2, 3, 5, 8]
4D[0, 2, 3, 5, 6]
5E[0, 2, 3, 5, 6]

결과: A→E 최단 거리 = 6 (A→B→D→E)

Python 구현

import heapq
import sys

def dijkstra(start, graph, n):
    INF = sys.maxsize
    dist = [INF] * n
    dist[start] = 0

    pq = [(0, start)]  # (거리, 노드)
    visited = [False] * n

    while pq:
        current_dist, u = heapq.heappop(pq)

        if visited[u]:
            continue
        visited[u] = True

        for v, w in graph[u]:
            if current_dist + w < dist[v]:
                dist[v] = current_dist + w
                heapq.heappush(pq, (dist[v], v))

    return dist


# 그래프 구성 (인접 리스트)
n = 5
graph = [[] for _ in range(n)]
edges = [
    (0, 1, 2), (0, 2, 5), (1, 2, 1),
    (1, 3, 3), (2, 3, 2), (2, 4, 5), (3, 4, 1)
]
for u, v, w in edges:
    graph[u].append((v, w))
    graph[v].append((u, w))

distances = dijkstra(0, graph, n)
print(distances)  # [0, 2, 3, 5, 6]

Java 구현

import java.util.*;

public class Dijkstra {
    public static int[] dijkstra(int start, List<List<int[]>> graph) {
        int n = graph.size();
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[start] = 0;

        PriorityQueue<int[]> pq = new PriorityQueue<>(
            Comparator.comparingInt(o -> o[1])
        );
        pq.offer(new int[]{start, 0});
        boolean[] visited = new boolean[n];

        while (!pq.isEmpty()) {
            int[] current = pq.poll();
            int u = current[0];

            if (visited[u]) continue;
            visited[u] = true;

            for (int[] edge : graph.get(u)) {
                int v = edge[0], w = edge[1];
                if (dist[u] + w < dist[v]) {
                    dist[v] = dist[u] + w;
                    pq.offer(new int[]{v, dist[v]});
                }
            }
        }
        return dist;
    }
}

Go 구현

import (
    "container/heap"
    "math"
)

type Item struct {
    node, dist, idx int
}

type PriorityQueue []*Item

func (pq PriorityQueue) Len() int           { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool { return pq[i].dist < pq[j].dist }
func (pq PriorityQueue) Swap(i, j int)      { pq[i], pq[j] = pq[j], pq[i] }
func (pq *PriorityQueue) Push(x interface{}) { *pq = append(*pq, x.(*Item)) }
func (pq *PriorityQueue) Pop() interface{} {
    old := *pq
    n := len(old)
    item := old[n-1]
    *pq = old[:n-1]
    return item
}

func Dijkstra(start int, graph [][]Edge) []int {
    dist := make([]int, len(graph))
    for i := range dist {
        dist[i] = math.MaxInt64
    }
    dist[start] = 0

    pq := &PriorityQueue{}
    heap.Push(pq, &Item{node: start, dist: 0})
    visited := make([]bool, len(graph))

    for pq.Len() > 0 {
        current := heap.Pop(pq).(*Item)
        u := current.node

        if visited[u] {
            continue
        }
        visited[u] = true

        for _, edge := range graph[u] {
            if dist[u]+edge.weight < dist[edge.node] {
                dist[edge.node] = dist[u] + edge.weight
                heap.Push(pq, &Item{node: edge.node, dist: dist[edge.node]})
            }
        }
    }
    return dist
}

주의사항

항목설명
음수 가중치Dijkstra 사용 불가 → Bellman-Ford 사용
방문 체크중복 연산 방지를 위해 필수
경로 역추적parent 배열에 갱신 시점의 u 저장

응용 분야

  • GPS/지도 서비스 길찾기
  • 네트워크 라우팅
  • 게임 AI 경로 탐색
  • 소셜 네트워크 최단 관계 분석

정리

Dijkstra 알고리즘은 비음수 가중치 그래프에서 최단 경로를 구하는 대표적 알고리즘입니다. 우선순위 큐를 사용하면 O(E log V)로 효율적으로 구현할 수 있습니다.