【算法】Dijkstra 求最短路径

66 阅读2分钟

原理

Dijkstra 核心就是用了贪心的思想。以局部最优解,求的所有的最优解。

例子

/**
 * 待实现函数,在此函数中填入答题代码
 * @param {number} routerNum
 * @param {number[][]} linkDelays
 * @param {number} routerRi
 * @param {number} routerRj
 * @return {number}
 */
const getMinDelay = (routerNum, linkDelays, routerRi, routerRj) => {
    let graph = [];
    // 无向图
    linkDelays.forEach(item => {
        let [start, end, delay] = item;
        if (!graph[start - 1]) {
            graph[start - 1] = []
        }
        if (!graph[end - 1]) {
            graph[end - 1] = []
        }
        graph[start - 1][end - 1] = delay;
        graph[end - 1][start - 1] = delay;
    })
    let visited = new Array(routerNum).fill(false);
    let distance = new Array(routerNum).fill(Number.MAX_SAFE_INTEGER);
    distance[routerRi - 1] = 0;
    visited[routerRi - 1] = true;
    // 取出源点到其他点的最短路径,后续更新pathNodes即可,返回 pathNodes[routerRj - 1]
    let pathNodes = graph[routerRi - 1];
    // 记录下次循环要遍历的点,即未确认最小距离的节点
    let notes = [];
    // 遍历 pathNodes, 获得 end 节点信息。
    pathNodes.forEach((_ , index) => {
        notes.push(index);
    })
    while (notes.length) {
        // minNoteIndex 就是 end 节点
        let minNoteIndex = notes[0];
        let min = pathNodes[minNoteIndex];

        // 在未确认最小距离的节点中找到值最小的note信息,以此为基点循环
        notes.forEach(note => {
            if (pathNodes[note] < min) {
                minNoteIndex = note;
                min = pathNodes[minNoteIndex];
            }
        })

        // 如果本次循环确认的最小节点是目标节点
        if (minNoteIndex === routerRj - 1) {
            return min || -1;
        }

        // 已确认的节点从notes中删除
        notes.splice(notes.indexOf(minNoteIndex), 1);

        // 以该最小值的note为基点,来确认到达其他点的最小距离。
        let endPathNotes = graph[minNoteIndex];

        // 从graph中取出note的边,el为权重,index为目标节点
        endPathNotes?.forEach((el, index) => {
            // 如果 el + min 小于pathNotes中记录的值,则更新;如果pathNodes[index] 没有值,则记录下来
            if (!pathNodes[index] || el + min < pathNodes[index]) {
                pathNodes[index] = el + min;
                notes.push(index)
            }
        })
    }
    return pathNodes[routerRj - 1]
};
// 路由数
let routerNum = 6;
// [start end 时延] = 1 2 2
let linkDelays = `1 2 2
1 3 4
2 5 3
5 6 2`.split('\n').map(item => item.split(' ').map((item) => Number(item)));
// 起始路由
let Ri = 2;
// 结束路由
let Rj = 6;
// 求 Ri -> Rj 的最小时延
console.log(getMinDelay(routerNum, linkDelays, Ri, Rj));