开发 gi 的时候,要用到一些图算法,唤起了多年前那段尘封的记忆,重温了胡凡的《算法笔记》。
Dijkstra
Dijkstra(中文译为戴克斯特拉算法) 是由荷兰计算机科学家艾兹赫尔·戴克斯特拉在1956年发现的算法。Dijkstra 算法用来解决单源最短路径问题,即给定图 G 和起点 start,通过算法得到 start 节点到其他每个节点的最短距离。
该过程可用下图来模拟。

具体的算法思想可用参考胡凡的《算法笔记》 P369。
感兴趣的大哥麻烦自己找找 pdf,我只有纸质书。
Javascript 实现
来自 antv 旗下的 algorithm 库 ,https://github.com/antvis/algorithm/blob/master/packages/graph/src/dijkstra.ts
值得一提的是,在 G6 中的图既不是用邻接表也不是用邻接矩阵,而是采用了如下结果
interface IGraph {nodes: any[];edges: any[];}
具体算法如下:
const minVertex = (D: { [key: string]: number },nodes: NodeConfig[],marks: { [key: string]: boolean },): NodeConfig => {// 找出最小的点let minDis = Infinity;let minNode;for (let i = 0; i < nodes.length; i++) {const nodeId = nodes[i].id;if (!marks[nodeId] && D[nodeId] <= minDis) {minDis = D[nodeId];minNode = nodes[i];}}return minNode;};const dijkstra = (graphData: GraphData,source: string,directed?: boolean,weightPropertyName?: string,) => {const { nodes = [], edges = [] } = graphData;const nodeIds = [];const marks = {};const D = {};const prevs = {}; // key: 顶点, value: 顶点的前驱点数组(可能有多条等长的最短路径)nodes.forEach((node, i) => {const id = node.id;nodeIds.push(id);D[id] = Infinity;if (id === source) D[id] = 0;});const nodeNum = nodes.length;for (let i = 0; i < nodeNum; i++) {// Process the verticesconst minNode = minVertex(D, nodes, marks);const minNodeId = minNode.id;marks[minNodeId] = true;if (D[minNodeId] === Infinity) continue; // Unreachable vertices cannot be the intermediate pointlet relatedEdges: EdgeConfig[] = [];if (directed) relatedEdges = getOutEdgesNodeId(minNodeId, edges);else relatedEdges = getEdgesByNodeId(minNodeId, edges);relatedEdges.forEach(edge => {const edgeTarget = edge.target;const edgeSource = edge.source;const w = edgeTarget === minNodeId ? edgeSource : edgeTarget;const weight = weightPropertyName && edge[weightPropertyName] ? edge[weightPropertyName] : 1;if (D[w] > D[minNode.id] + weight) {D[w] = D[minNode.id] + weight;prevs[w] = [minNode.id];} else if (D[w] === D[minNode.id] + weight) {prevs[w].push(minNode.id);}});}prevs[source] = [source];// 每个节点存可能存在多条最短路径const paths = {};for (const target in D) {if (D[target] !== Infinity) {findAllPaths(source, target, prevs, paths);}}// 兼容之前单路径const path = {};for (const target in paths) {path[target] = paths[target][0];}return { length: D, path, allPath: paths };};
c++ 实现
其中的图使用邻接表实现,参考了《算法笔记》的思路自己写了一般,摒弃了原书中 c+STL 的写法,改用 c++ 11 的新语法实现。
#include <bits/stdc++.h>using namespace std;class Edge{public:int to;int cost;Edge(int to, int cost){this->to = to;this->cost = cost;}};void Dijkstra(int start, vector<vector<Edge>> graph){int n = graph.size();// 距离vector<int> dis(n, INT_MAX);// 已经访问过的节点vector<bool> visited(n, false);dis[start] = 0;for (int i = 0; i < n; i++){// 寻找当前已知的最近节点int nearestNode = -1;int minDis = INT_MAX;for (int j = 0; j <= n; j++){if (!visited[j] && dis[j] < minDis){nearestNode = j;minDis = dis[j];}}visited[nearestNode] = true;for (Edge &edge : graph[nearestNode]){if (!visited[edge.to] && dis[nearestNode] + edge.cost < dis[edge.to]){dis[edge.to] = dis[nearestNode] + edge.cost;}}}}
