当前位置:首页 > JavaScript

js实现最短路径算法

2026-03-01 10:48:24JavaScript

Dijkstra算法实现

Dijkstra算法适用于加权图中寻找单源最短路径,要求权重为非负数。以下是JavaScript实现示例:

js实现最短路径算法

class PriorityQueue {
  constructor() {
    this.items = [];
  }
  enqueue(element, priority) {
    const queueElement = { element, priority };
    let added = false;
    for (let i = 0; i < this.items.length; i++) {
      if (queueElement.priority < this.items[i].priority) {
        this.items.splice(i, 0, queueElement);
        added = true;
        break;
      }
    }
    if (!added) this.items.push(queueElement);
  }
  dequeue() {
    return this.items.shift();
  }
  isEmpty() {
    return this.items.length === 0;
  }
}

function dijkstra(graph, startNode) {
  const distances = {};
  const previous = {};
  const pq = new PriorityQueue();

  Object.keys(graph).forEach(node => {
    distances[node] = node === startNode ? 0 : Infinity;
    previous[node] = null;
    pq.enqueue(node, distances[node]);
  });

  while (!pq.isEmpty()) {
    const { element: currentNode } = pq.dequeue();
    Object.entries(graph[currentNode]).forEach(([neighbor, weight]) => {
      const alt = distances[currentNode] + weight;
      if (alt < distances[neighbor]) {
        distances[neighbor] = alt;
        previous[neighbor] = currentNode;
        pq.enqueue(neighbor, alt);
      }
    });
  }
  return { distances, previous };
}

Floyd-Warshall算法实现

Floyd-Warshall算法可以计算图中所有顶点对之间的最短路径:

js实现最短路径算法

function floydWarshall(graph) {
  const dist = {};
  const vertices = Object.keys(graph);

  vertices.forEach(i => {
    dist[i] = {};
    vertices.forEach(j => {
      dist[i][j] = graph[i][j] || (i === j ? 0 : Infinity);
    });
  });

  vertices.forEach(k => {
    vertices.forEach(i => {
      vertices.forEach(j => {
        if (dist[i][j] > dist[i][k] + dist[k][j]) {
          dist[i][j] = dist[i][k] + dist[k][j];
        }
      });
    });
  });

  return dist;
}

A*搜索算法实现

A*算法结合了Dijkstra和启发式搜索,适用于路径规划:

function aStar(start, goal, graph, heuristic) {
  const openSet = new Set([start]);
  const cameFrom = {};
  const gScore = { [start]: 0 };
  const fScore = { [start]: heuristic(start, goal) };

  while (openSet.size > 0) {
    let current = null;
    let lowestFScore = Infinity;
    openSet.forEach(node => {
      if (fScore[node] < lowestFScore) {
        lowestFScore = fScore[node];
        current = node;
      }
    });

    if (current === goal) {
      return reconstructPath(cameFrom, current);
    }

    openSet.delete(current);
    graph[current].forEach(neighbor => {
      const tentativeGScore = gScore[current] + neighbor.cost;
      if (tentativeGScore < (gScore[neighbor.node] || Infinity)) {
        cameFrom[neighbor.node] = current;
        gScore[neighbor.node] = tentativeGScore;
        fScore[neighbor.node] = gScore[neighbor.node] + heuristic(neighbor.node, goal);
        if (!openSet.has(neighbor.node)) {
          openSet.add(neighbor.node);
        }
      }
    });
  }
  return null;
}

function reconstructPath(cameFrom, current) {
  const path = [current];
  while (cameFrom[current]) {
    current = cameFrom[current];
    path.unshift(current);
  }
  return path;
}

Bellman-Ford算法实现

该算法能处理负权边并检测负权环:

function bellmanFord(graph, start) {
  const distances = {};
  const predecessors = {};
  Object.keys(graph).forEach(node => {
    distances[node] = node === start ? 0 : Infinity;
    predecessors[node] = null;
  });

  for (let i = 0; i < Object.keys(graph).length - 1; i++) {
    Object.entries(graph).forEach(([u, edges]) => {
      Object.entries(edges).forEach(([v, weight]) => {
        if (distances[u] + weight < distances[v]) {
          distances[v] = distances[u] + weight;
          predecessors[v] = u;
        }
      });
    });
  }

  let hasNegativeCycle = false;
  Object.entries(graph).forEach(([u, edges]) => {
    Object.entries(edges).forEach(([v, weight]) => {
      if (distances[u] + weight < distances[v]) {
        hasNegativeCycle = true;
      }
    });
  });

  return { distances, predecessors, hasNegativeCycle };
}

使用注意事项

  • Dijkstra算法适用于非负权图,时间复杂度为O((V+E)logV)
  • Floyd-Warshall适用于稠密图,时间复杂度O(V³)
  • A*算法需要合适的启发式函数
  • Bellman-Ford能检测负权环但时间复杂度较高(O(VE))

根据具体场景选择合适算法,例如导航系统常用A*,网络路由常用Dijkstra,需要考虑负权值时使用Bellman-Ford。

标签: 最短算法
分享给朋友:

相关文章

php 实现算法

php 实现算法

PHP 实现常见算法的方法 PHP 作为一门服务器端脚本语言,可以实现多种算法。以下是一些常见算法的 PHP 实现示例。 排序算法 冒泡排序 function bubbleSort($arra…

用js来实现所有算法

用js来实现所有算法

在 JavaScript 中实现所有算法是一个庞大的任务,因为算法种类繁多,涵盖数据结构、排序、搜索、图论、动态规划等多个领域。以下是部分常见算法的 JavaScript 实现示例,供参考: 排序…

算法js实现

算法js实现

JavaScript 算法实现基础 JavaScript 作为一门灵活且强大的编程语言,能够实现各种常见算法。以下是一些基础算法的 JavaScript 实现示例。 排序算法 快速排序是一种高效的排…

js算法实现

js算法实现

以下是JavaScript中常见的算法实现示例,涵盖排序、搜索、递归等经典场景: 排序算法 快速排序 function quickSort(arr) { if (arr.length <…

js回文算法实现

js回文算法实现

回文算法的实现方法 方法一:使用字符串反转 将字符串反转后与原字符串比较,若相同则为回文。 function isPalindrome(str) { const reversedStr = s…

js实现火焰算法

js实现火焰算法

火焰算法实现基础 火焰算法(Fire Effect)是一种模拟火焰燃烧效果的图形算法,常用于生成动态火焰视觉效果。在JavaScript中,可以通过Canvas或WebGL实现。 使用Canvas实…