개발자의 공부/자료구조&알고리즘

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

2023. 10. 5. 09:25
목차
  1. ✅ 다익스트라 알고리즘(Dijkstra's Algorithm)이란?
  2. 구현
  3. 우선순위 큐 성능 향상

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

그래프 내의 한 출발점에서 모든 다른 노드까지의 최단 경로를 찾는 데 사용되는 알고리즘으로 가중치가 있는 그래프에서 각 노드 사이의 최단 경로를 찾을 때 효과적으로 사용된다.

 

사용 사례

도로 네트워크 경로 탐색: 다익스트라 알고리즘은 GPS 시스템과 네비게이션 앱에서 사용된다. 운전자가 출발지와 목적지를 입력하면, 다익스트라 알고리즘을 활용하여 최단 경로와 예상 도착 시간을 계산하고 제공한다.

 

인터넷 라우팅: 다익스트라 알고리즘은 데이터 패킷을 최적 경로로 전달하는 라우팅 프로토콜에서 사용된다. 네트워크 노드 간의 연결을 나타내는 그래프에서 최단 경로를 계산하여 데이터의 효율적인 전달을 도와준다.

 

공항 및 항구 관리: 항공국 및 항구 관리자들은 비행기나 선박의 이동 경로를 최적화하기 위해 다익스트라 알고리즘을 사용한다. 이를 통해 운송 수단의 스케줄링 및 자원 할당을 효율적으로 관리할 수 있다.

 

소셜 네트워크 분석: 소셜 네트워크에서 다익스트라 알고리즘은 친구 추천 및 정보 전파 분석에 사용된다. 어떤 사람과 다른 사람 사이의 최단 경로를 찾아 친구 추천 알고리즘을 개선하거나 정보 전파의 효과를 연구할 수 있다.

 

그래프의 두 지점 사이의 최단 거리를 찾기 전에 먼저 해야할 일은 vertex 사이에 값을 부여해서 그 경로의 가중치를 알 수 있게 해야한다.

 

가중치 그래프 예시

class WeightedGraph {
    constructor() {
        this.adjacencyList = {};
    }
    addVertex(vertex) {
        if(!this.adjacencyList[vertex]) this.adjacencyList[vertex] = []
    }
    addEdge(vertex1, vertex2, weight) {
        this.adjacencyList[vertex1].push({node:vertex2, weight})
        this.adjacencyList[vertex2].push({node:vertex1, weight})
        
    }
}

위는 그래프에 가중치를 추가하여 가중치 그래프를 구현한 간단한 예이다. 우선순위 큐 구현 예시를 살펴보자. 결코 좋은 코드는 아니며 아주 기본적인 예시다.

class PriorityQueue{
    constructor() {
        this.values = [];
    }
    enqueue(val, priority) {
        this.values.push({val,priority});
        this.sort()
    }
    dequeue() {
        return this.values.shift()
    }
    sort() {
        this.values.sort((a,b) => a.priority - b.priority)
    }
}

다익스트라 알고리즘 의사코드

  • 시작 vertex와 끝 vertex를 받는 함수를 선언한다.
  • 객체를 생성하고(distances라고 부르는) 모든 vertex를 key로 하여 infinity 값으로 초기화 하며, 시작 vertex의 값은 0으로 설정한다.
  • 모든 값들을 distances 객체에서 설정을 한 뒤에, 새로운 우선순위 큐를 만들고 빈 상태로 설정해 준다. 거기에 infinity인 vertex를 큐에 추가하고, 시작 vertex의 경우는 시작점이기 때문에 0으로 설정하여 큐에 추가한다.
  • previous 객체를 추가하고 해당 객체에 인접 리스트의 모든 vertex의 key를 설정하고 각 프로퍼티의 값들은 null로 설정한다.
  • 큐에 대기열이 있는 한 loop를 한다.
    • 우선순위 큐로부터 vertex를 dequeue한다.
    • 만약 vertex가 끝 vertex와 같다면 끝난다!
    • 그렇지 않으면 해당 정점의 인접 목록에 있는 각 값을 순환한다.
      • 시작 vertex와 vertex 사이의 거리를 계산한다.
      • 만약 거리가 최근에 저장된 거리보다 작다면
        • 더 작은 거리 값으로 distances 객체를 업데이트한다.
        • 해당 vertex를 포함하도록 previous 객체를 업데이트 한다.
        • 시작 노드로부터의 전체 거리로 정점을 enqueue한다.

구현

Dijkstra(start, finish){
    const nodes = new PriorityQueue();
    const distances = {};
    const previous = {};
    let path = [] //to return at end
    let smallest;
    
    // 초기값 설정
    // distances: 출발점 0, 나머지 Infinity
    // nodes(우선순위 큐): vertex와 가중치가 0 [{vla: vertex, priority: 0}...]
    // previous: {vertex: null,...}
    for(let vertex in this.adjacencyList){
        if(vertex === start){
            distances[vertex] = 0;
            nodes.enqueue(vertex, 0);
        } else {
            distances[vertex] = Infinity;
            nodes.enqueue(vertex, Infinity);
        }
        previous[vertex] = null;
    }
	// 방문해야할 노드가 있다면
    while(nodes.values.length){
        smallest = nodes.dequeue().val;
        if(smallest === finish){
                //WE ARE DONE
                //BUILD UP PATH TO RETURN AT END
            while(previous[smallest]){
                path.push(smallest);
                smallest = previous[smallest];
            }
            break;
        } 
        if(smallest || distances[smallest] !== Infinity){
            for(let neighbor in this.adjacencyList[smallest]){
                // 각 노드들의 인접 노드를 찾음.
                let nextNode = this.adjacencyList[smallest][neighbor];
                // 인접 노드들에 대한 새로운 거리를 계산함.
                let candidate = distances[smallest] + nextNode.weight;
                let nextNeighbor = nextNode.node;
                if(candidate < distances[nextNeighbor]){
                    distances[nextNeighbor] = candidate;
                    previous[nextNeighbor] = smallest;
                    nodes.enqueue(nextNeighbor, candidate);
                }
            }
        }
    }
    return path.concat(smallest).reverse();     
}

 

우선순위 큐 성능 향상

class Node {
    constructor(val, priority) {
        this.val = val;
        this.priority = priority;
    }
}

class PriorityQueue {
    constructor() {
        this.values = [];
    }

    enqueue(val, priority) {
        let newNode = new Node(val,priority);
        this.values.push(newNode)
        this.bubbleUp();
    }
    bubbleUp() {
        let idx = this.values.length - 1;
        const element = this.values[idx];
        while (idx > 0) {
            let parentIdx = Math.floor((idx - 1) / 2);
            let parent = this.values[parentIdx];
            if (element.priority >= parent.priority)
                break;
            this.values[parentIdx] = element;
            this.values[idx] = parent;
            idx = parentIdx;
        }
    }
    dequeue() {
        const min = this.values[0];
        const end = this.values.pop();
        if (this.values.length > 0) {
            this.values[0] = end;
            this.sinkDown();
        }
        return min;
    }

    sinkDown() {
        let idx = 0;
        const length = this.values.length;
        while (true) {
            const element = this.values[idx];
            const leftChildIdx = 2 * idx + 1;
            const rightChildIdx = 2 * idx + 2;
            let leftChild;
            let rightChild;
            let swap = null;

            if (leftChildIdx < length) {
                leftChild = this.values[leftChildIdx];
                if (leftChild.priority < element.priority) {
                    swap = leftChildIdx;
                }
            }

            if (rightChildIdx < length) {
                rightChild = this.values[rightChildIdx];
                if ((swap === null && rightChild.priority < element.priority) || (swap !== null && rightChild.priority < leftChild.priority)) {
                    swap = rightChildIdx;
                }
            }
            if (swap === null)
                break;

            [this.values[idx],this.values[swap]] = [this.values[swap], this.values[idx]];
            idx = swap;
        }
    }
}
저작자표시 비영리 동일조건 (새창열림)

'개발자의 공부 > 자료구조&알고리즘' 카테고리의 다른 글

[자료구조] 그래프(Graphs)  (0) 2023.05.22
[자료구조] 해시 테이블(Hash Tables)  (0) 2023.05.11
[자료구조] 힙(Heap)  (0) 2023.04.28
[알고리즘]깊이 우선 탐색(DFS, Depth-First Search)  (0) 2023.03.16
[알고리즘]너비 우선 탐색(BFS, Breadth-First Search)  (0) 2023.03.12
  1. ✅ 다익스트라 알고리즘(Dijkstra's Algorithm)이란?
  2. 구현
  3. 우선순위 큐 성능 향상
'개발자의 공부/자료구조&알고리즘' 카테고리의 다른 글
  • [자료구조] 그래프(Graphs)
  • [자료구조] 해시 테이블(Hash Tables)
  • [자료구조] 힙(Heap)
  • [알고리즘]깊이 우선 탐색(DFS, Depth-First Search)
JMins
JMins
안녕하세요. 프론트엔드 개발자 김정민입니다. 개발 지식을 공유하고 기록하는 공간입니다.
JMins
개발자 노트
JMins
전체
오늘
어제
  • 분류 전체보기 (85)
    • 개발자의 공부 (73)
      • React (17)
      • 자료구조&알고리즘 (28)
      • JS (17)
      • TS (8)
      • Nodejs (0)
      • Nextjs (1)
      • 기타 (1)
      • Design Pattenrs (0)
      • 테스트 및 최적화 (1)
    • 문제 및 해결 (9)
    • 기본 지식 (3)
    • 챌린지 (0)

블로그 메뉴

  • 홈

공지사항

  • #블로그 스킨 변경
  • 개인적으로 공부를 기록하기 위해 적고 있습니다.

인기 글

최근 댓글

최근 글

hELLO · Designed By 정상우.
JMins
다익스트라 알고리즘(Dijkstra's Algorithm)
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.