1. 简介

在图论中,最短路径问题指的是在图中寻找两个顶点之间的路径,使得路径上所有边的权重之和最小。我们可以通过 Dijkstra 算法Uniform-Cost 搜索算法 来解决这类问题。

本文将介绍这两种算法的基本实现方式,并对它们在单源最短路径和单对最短路径问题中的表现进行对比分析。


2. Dijkstra 算法概述

Dijkstra 算法适用于带权有向图,且边权值为非负数。它从一个源点 s 出发,计算出到图中所有其他顶点的最短路径。

算法流程如下:

algorithm Dijkstra(G, s):
    // INPUT
    //     G = weighted directed graph (G = (V, E))
    //     s = the source vertex
    // OUTPUT
    //     dist = the shortest paths' weights from s to all vertices

    for v in V:
        dist[v] <- +infinity
    dist[s] <- 0
    Q <- empty vertex set
    for v in V:
        add v to Q with key dist[v]

    while Q is not empty:
        u <- the vertex in Q with smallest dist[u]
        
        remove u from Q
        visited[u] <- true
        if dist[u] == +infinity:
            break

        for v in Adj(u) and not visited[v]:
            dist <- dist[u] + w(u, v)
            if dist < dist[v]:
                dist[v] <- dist
                update Q for vertex v

    return dist

该算法使用优先队列(如最小堆)来维护顶点集合 Q,每次取出当前距离最小的顶点进行松弛操作。

时间复杂度为:✅ **O((|V| + |E|) log |V|)**,其中 |V| 是顶点数,|E| 是边数。


3. 单对最短路径的 Dijkstra 实现

当我们只需要从源点 s 到目标点 d 的最短路径时,可以对 Dijkstra 做如下优化:

  • 一旦取出顶点 u == d,即可终止循环
  • 使用 prev[] 数组记录路径前驱,用于构建完整路径

伪代码如下:

algorithm DijkstraPair(G, s, d):
    // INPUT
    //     G = (V, E) = a weighted directed graph
    //     s = the source vertex
    //     d = the destination vertex
    // OUTPUT
    //     The list of vertices on the shortest path between s and d

    for v in V:
        dist[v] <- +infinity
    dist[s] <- 0
    Q <- empty vertex set
    for v in V:
        add v to Q with key dist[v]

    while Q is not empty:
        u <- find the vertex in Q with smallest dist[u]
        remove u from Q
        if u = d:
            break
        visited[u] <- true
        if dist[u] = +infinity:
            break

        for v in Adj(u) and not visited[v]:
            dist <- dist[u] + w(u, v)
            if dist < dist[v]:
                dist[v] <- dist
                update Q for vertex v
                prev[v] <- u

    return buildPath(s, d, prev)

路径构建函数:

algorithm buildPath(s, d, prev):
    path <- create an empty list
    v <- d
    while v != s:
        insert v at the front of path
        v <- prev[v]
    insert s at the front of path

    return path

4. Uniform-Cost 搜索算法

Uniform-Cost 是一种基于最佳优先搜索(Best-First Search)的变体,每次选择从起点出发路径代价最小的顶点进行扩展。

它与 Dijkstra 的主要区别在于:

  • 初始化时只将源点加入队列
  • 在扩展过程中动态加入新发现的顶点
  • 更适合处理隐式图(如状态空间搜索)

4.1 流程图与伪代码

CS 646 Uniform Cost Search

伪代码如下:

algorithm UniformCost(G, s):
    // INPUT
    //     G = (V, E) = a weighted directed graph
    //     s = the source vertex
    // OUTPUT
    //     dist = the shortest paths' weights from s to all vertices

    dist[s] <- 0
    Q <- create an empty vertex set
    add s to Q with key dist[s]

    while Q is not empty:
        u <- find the vertex in Q with smallest dist[u]
        
        remove u from Q

        for v in Adj(u):
            dist <- dist[u] + w(u, v)
            if v in Q:
                if dist < dist[v]:
                    dist[v] <- dist
                    update Q for vertex v
            else:
                dist[v] <- dist
                add v to Q with key dist[v]

    return dist

4.2 单对最短路径实现

同样可以扩展为单对最短路径问题:

algorithm UniformCostPair(G, s, d):
    // INPUT
    //     G = (V, E) = a weighted directed graph
    //     s = the source vertex
    //     d = the destination vertex
    // OUTPUT
    //     The path from s to d

    dist[s] <- 0
    Q <- create an empty vertex set
    add s to Q with key dist[s]

    while Q is not empty:
        u <- find the vertex in Q with smallest dist[u]
        
        remove u from Q
        if u = d:
            break

        for v in Adj(u):
            dist <- dist[u] + w(u, v)
            if v in Q:
                if dist < dist[v]:
                    dist[v] <- dist
                    prev[v] <- u
                    update Q for vertex v
            else:
                dist[v] <- dist
                add v to Q with key dist[v]
                prev[v] <- u

    return buildPath(s, d, prev)

5. 两种算法对比

特性 Dijkstra 算法 Uniform-Cost 搜索
初始化 所有顶点加入队列 只加入源点
内存需求 高(需存整个图) 低(只存必要顶点)
运行时间 较慢(因内存开销) 较快
图类型支持 显式图 显式图 + 隐式图
不可达顶点 dist[v] = +∞ dist[v] 不存在

主要区别

  • 初始化方式不同:Dijkstra 一次性将所有顶点加入优先队列;Uniform-Cost 动态加入
  • 适用图类型不同:Dijkstra 仅适用于显式图;Uniform-Cost 适用于显式和隐式图
  • 内存效率:Dijkstra 占用更高,尤其在大规模图中表现不佳
  • ⚠️ 性能表现:虽然时间复杂度相同,但实际运行中 Uniform-Cost 因为内存效率更高,通常更快

6. 总结

Dijkstra 和 Uniform-Cost 都能用于解决最短路径问题,并且在理论上具有相同的时间复杂度。但在实际应用中:

  • Uniform-Cost 更适合大规模图或隐式图场景
  • Dijkstra 更适合图结构已知且内存充足的情况
  • ⚠️ 对于单对最短路径问题,Uniform-Cost 通常表现更优

因此,在选择算法时,应根据图的规模、是否已知、内存限制等因素综合判断。


原始标题:Comparison Between Uniform-Cost Search and Dijkstra’s Algorithm