다익스트라 알고리즘 : 자바스크립트

otter·2022년 2월 6일
0

다익스트라 알고리즘 접근법

  • 새로운 node에 접근할때마다, 첫번째로 방문한 node와 - start 노드와 - 길이가 가장 작은 node를 탐색한다.
  • 우리가 다음 노드로 이동하면, 우리는 해당 노드의 neighbors들을 확인한다.
  • neighbors가 존재한다면, 시작한 노드로부터의 거리를 계산한다.
  • 계산된 새로운 거리가, 이전에 계산된 거리보다 적다면 node를 방문한다.
  • 이 접근법을 위해, 우리는 distance,visited 와, Previous를 따로 만들어 지속적으로 확인해야한다.

의사코드

  • function은 매개변수로 starting과 ending vertex를 받는다.
  • distacne라는 객체를 만들고, 인접리스트의 key값(vertex들)을 이용한다.
    - starting vertex는 0을 나머지 값은 infinity를 가진다.
  • 우선순위큐에 각 vertex를 추가한다.
    - starting vertex의 우선순위는 0, 나머지의 우선순위는 infinity를 가진다.
    - starting 포인트에서 시작하기 때문에, starting의 우선순위를 0으로 하는 것.
  • previous라는 객체를 만들고, 각 vertex를 추가한다.
    - 각 vertex는 null의 값을 가진다.
    • 우리가 아직, previous를 모르므로 초깃값을 null로 만드는 것
  • priority queue를 기준으로 루프가 실행된다.
    - priority queue에서 dequeue 한다.
    • 우선순위가 제일 높은 값이 최상단에 있도록 계속해서 정렬하므로, 무조건 우선순위가 제일 높은 값이 나오게 된다.
    • dequeue되는 vertex가 ending vertex라면 종료한다.
    • 그렇지 않다면,
      • starting vertexdequeue되는 vertex의 distance를 구한다.
      • 구해진 값이 disntace 오브젝트에 저장되어 있는 값보다 적다면,
      • distance 오브젝트의 값을 작은 값으로 교체한다.
      • previous 값을 해당 vertex로 교체한다.
      • 우선순위큐에 해당 값을 enqueue 한다.

초기설정 구현

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);
    };
  }
// 간단한 우선순위 큐 구현
      Dijkstra(start, finish) {
          const nodes = new PriorityQueue();
          const distance = {};
          const previous = {};
          
          // bulid up initail state.
          for(let vertex in this.adjacencyList) {
              if(vertex === start) {
                  distance[vertex] = 0;
                  nodes.enqueue(vertex, 0);
              } else {
                  distance[vertex] = Infinity;
                  nodes.enqueue(vertex, Infinity);
                  // 우선순위 큐 만들어주기.
                  // 니중에 우선순위를 줄여주어서 방문할 값을 만들어 줄것임.
              }

              previous[vertex] = null;
          }
  • 추후에 사용할 우선순위큐 클래스를 작성한다.
  • 다익스트라 알고리즘 구현을 다음을 작성한다.
    - 우선순위큐 : 앞으로 방문할 노드들의 우선순위를 정하기 위해
    • distance : start와의 거리를 구하는 객체
    • previous : 해당 노도의 이전 노드를 저장해두는 객체
// distance
{
  A: 0,
  B: Infinity,
  C: Infinity,
  D: Infinity,
  E: Infinity,
  F: Infinity
}

// previous
{ A: null, B: null, C: null, D: null, E: null, F: null }

// priorityQueue
PriorityQueue {
  values: [
    { val: 'A', priority: 0 },
    { val: 'B', priority: Infinity },
    { val: 'C', priority: Infinity },
    { val: 'D', priority: Infinity },
    { val: 'E', priority: Infinity },
    { val: 'F', priority: Infinity }
  ]
}

loop 구현

   // as long as there is something to visit
        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]){
                    //find neighboring node
                    let nextNode = this.adjacencyList[smallest][neighbor];
                    //calculate new distance to neighboring node
                    let candidate = distances[smallest] + nextNode.weight;
                    let nextNeighbor = nextNode.node;
                    if(candidate < distances[nextNeighbor]){
                        //updating new smallest distance to neighbor
                        distances[nextNeighbor] = candidate;
                        //updating previous - How we got to neighbor
                        previous[nextNeighbor] = smallest;
                        //enqueue in priority queue with new priority
                        nodes.enqueue(nextNeighbor, candidate);
                    }
                }
            }
        }

최종 코드

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);
  };
}

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});
    }
    Dijkstra(start, finish){
        const nodes = new PriorityQueue();
        const distances = {};
        const previous = {};
        let path = [] //to return at end
        let smallest;
        //build up initial state
        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;
        }
        // as long as there is something to visit
        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]){
                    //find neighboring node
                    let nextNode = this.adjacencyList[smallest][neighbor];
                    //calculate new distance to neighboring node
                    let candidate = distances[smallest] + nextNode.weight;
                    let nextNeighbor = nextNode.node;
                    if(candidate < distances[nextNeighbor]){
                        //updating new smallest distance to neighbor
                        distances[nextNeighbor] = candidate;
                        //updating previous - How we got to neighbor
                        previous[nextNeighbor] = smallest;
                        //enqueue in priority queue with new priority
                        nodes.enqueue(nextNeighbor, candidate);
                    }
                }
            }
        }
        return path.concat(smallest).reverse();     
    }
}

var graph = new WeightedGraph()
graph.addVertex("A");
graph.addVertex("B");
graph.addVertex("C");
graph.addVertex("D");
graph.addVertex("E");
graph.addVertex("F");

graph.addEdge("A","B", 4);
graph.addEdge("A","C", 2);
graph.addEdge("B","E", 3);
graph.addEdge("C","D", 2);
graph.addEdge("C","F", 4);
graph.addEdge("D","E", 3);
graph.addEdge("D","F", 1);
graph.addEdge("E","F", 1);


graph.Dijkstra("A", "E");

// ["A", "C", "D", "F", "E"]

이 문서는 유데미에서 다음 강의를 듣고 기록한 문서입니다.
부족한 내용이 있을 수 있습니다. 🥲
【글로벌 Best】 JavaScript 알고리즘 & 자료구조 마스터클래스 (한글자막)

공부한 흔적들







profile
http://otter-log.world 로 이사했어요!

0개의 댓글