Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C/C++로 구현하는 다익스트라(Dijkstra) 최단 경로 알고리즘

시작 정점(source vertex)이 하나 주어진 그래프가 있을 때, 우리는 이 시작 정점으로부터 그래프의 나머지 모든 정점까지의 최단 경로를 찾아야 합니다.

다익스트라(Dijkstra) 알고리즘은 시작 정점에서 그래프 내 다른 모든 정점(노드)까지의 최단 경로를 구하는 대표적인 탐욕(Greedy) 알고리즘입니다. 이 알고리즘은 매 반복마다 아직 방문하지 않은 정점 중 시작점에 가장 가까운 정점을 하나씩 선택해 나가는 방식으로 동작합니다.

알고리즘 동작 단계

단계 1 : 최단 경로 트리(shortest path tree)에 포함될 정점들을 저장하기 위한 집합 shortPath를 생성합니다.
단계 2 : 모든 거리(dist) 값을 INFINITE(무한대)로 초기화하고, 시작 정점의 거리 값만 0으로 설정하여 가장 먼저 선택되도록 합니다.
단계 3 : 그래프의 모든 정점이 shortPath에 포함될 때까지 다음 과정을 반복합니다.
    단계 3.1 : 아직 방문하지 않은 정점 중 가장 가까운 새로운 정점을 선택합니다.
    단계 3.2 : 선택한 정점을 shortPath에 추가합니다.
    단계 3.3 : 해당 정점의 모든 인접 정점에 대해 거리 값을 갱신합니다. 즉, 각 인접 정점 v에 대해 (정점 u까지의 거리 + 간선의 가중치)가 기존 dist[v]보다 작으면 그 값으로 업데이트합니다.

위 알고리즘을 바탕으로 실제 프로그램을 만들어 보겠습니다.

C/C++ 구현 예제

#include <limits.h>
#include <stdio.h>
#define V 9
int minDistance(int dist[], bool sptSet[]) {
    int min = INT_MAX, min_index;
    for (int v = 0; v < V; v++)
        if (sptSet[v] == false && dist[v] <= min)
            min = dist[v], min_index = v;
    return min_index;
}
int printSolution(int dist[], int n) {
    printf("Vertex Distance from Source\n");
    for (int i = 0; i < V; i++)
        printf("%d \t %d\n", i, dist[i]);
}
void dijkstra(int graph[V][V], int src) {
    int dist[V];
    bool sptSet[V];
    for (int i = 0; i < V; i++)
        dist[i] = INT_MAX, sptSet[i] = false;
    dist[src] = 0;
    for (int count = 0; count < V - 1; count++) {
        int u = minDistance(dist, sptSet);
        sptSet[u] = true;
        for (int v = 0; v < V; v++)
            if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) dist[v] = dist[u] + graph[u][v];
    }
    printSolution(dist, V);
}
int main() {
    int graph[V][V] = { { 0, 6, 0, 0, 0, 0, 0, 8, 0 },
                        { 6, 0, 8, 0, 0, 0, 0, 13, 0 },
                        { 0, 8, 0, 7, 0, 6, 0, 0, 2 },
                        { 0, 0, 7, 0, 9, 14, 0, 0, 0 },
                        { 0, 0, 0, 9, 0, 10, 0, 0, 0 },
                        { 0, 0, 6, 14, 10, 0, 2, 0, 0 },
                        { 0, 0, 0, 0, 0, 2, 0, 1, 6 },
                        { 8, 13, 0, 0, 0, 0, 1, 0, 7 },
                        { 0, 0, 2, 0, 0, 0, 6, 7, 0 } };
    dijkstra(graph, 0);
    return 0;
}

실행 결과

Vertex Distance from Source
0   0
1   6
2   14
3   21
4   21
5   11
6   9
7   8
8   15

실행 결과를 보면 시작 정점 0번으로부터 각 정점까지의 최단 거리가 출력됩니다. 예를 들어 정점 1까지의 거리는 6, 정점 5까지는 11, 정점 7까지는 8, 정점 8까지는 15입니다.

시간 복잡도 및 참고 사항

위 코드처럼 인접 행렬(adjacency matrix)을 사용하면 시간 복잡도는 O(V²)가 됩니다(V는 정점의 개수). 정점 수가 많은 대규모 그래프에서는 우선순위 큐(priority queue)나 인접 리스트를 함께 사용하면 성능을 크게 개선할 수 있습니다. 또한 다익스트라 알고리즘은 음수 가중치를 가진 간선이 없는 그래프에서만 올바른 결과를 보장한다는 점도 유의해야 합니다.