C语言中如何实现最短路径算法?

99ANYc3cd6
预计阅读时长 21 分钟
位置: 首页 C语言 正文

C语言实现最短路径算法

最短路径算法是图论中的经典问题,常见的算法包括Dijkstra算法、Bellman-Ford算法、Floyd-Warshall算法等,下面我将分别介绍这三种算法的C语言实现。

c语言 shortestpath
(图片来源网络,侵删)

Dijkstra算法(单源最短路径)

Dijkstra算法用于计算从单个源点到所有其他顶点的最短路径,适用于非负权重的图。

#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#define V 9  // 顶点数量
// 找到未访问顶点中距离最小的顶点
int minDistance(int dist[], bool sptSet[]) {
    int min = INT_MAX, min_index;
    for (int v = 0; v < V; v++) {
        if (sptSet[v] == false && dist[v] <= min) {
            min = dist[v];
            min_index = v;
        }
    }
    return min_index;
}
// 打印最短路径
void printSolution(int dist[]) {
    printf("顶点\t距离\n");
    for (int i = 0; i < V; i++) {
        printf("%d\t%d\n", i, dist[i]);
    }
}
// Dijkstra算法实现
void dijkstra(int graph[V][V], int src) {
    int dist[V];     // 存储最短距离
    bool sptSet[V];  // sptSet[i]为true表示顶点i在最短路径树中
    // 初始化距离数组和sptSet数组
    for (int i = 0; i < V; i++) {
        dist[i] = INT_MAX;
        sptSet[i] = false;
    }
    // 源点到自身的距离为0
    dist[src] = 0;
    // 对所有顶点进行处理
    for (int count = 0; count < V - 1; count++) {
        // 选择未访问顶点中距离最小的顶点
        int u = minDistance(dist, sptSet);
        // 标记该顶点为已访问
        sptSet[u] = true;
        // 更新相邻顶点的距离
        for (int v = 0; v < V; v++) {
            // 更新条件:1.顶点v未被访问 2.存在边u-v 3.通过u到v的距离更短
            if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && 
                dist[u] + graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
            }
        }
    }
    // 打印结果
    printSolution(dist);
}
int main() {
    /* 示例图 */
    int graph[V][V] = {
        {0, 4, 0, 0, 0, 0, 0, 8, 0},
        {4, 0, 8, 0, 0, 0, 0, 11, 0},
        {0, 8, 0, 7, 0, 4, 0, 0, 2},
        {0, 0, 7, 0, 9, 14, 0, 0, 0},
        {0, 0, 0, 9, 0, 10, 0, 0, 0},
        {0, 0, 4, 14, 10, 0, 2, 0, 0},
        {0, 0, 0, 0, 0, 2, 0, 1, 6},
        {8, 11, 0, 0, 0, 0, 1, 0, 7},
        {0, 0, 2, 0, 0, 0, 6, 7, 0}
    };
    dijkstra(graph, 0);
    return 0;
}

Bellman-Ford算法(处理负权重)

Bellman-Ford算法可以处理带有负权重的图,并能检测负权重环。

#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#define V 5  // 顶点数量
#define E 8  // 边数量
// 结构体表示边
struct Edge {
    int src, dest, weight;
};
// 打印结果
void printArr(int dist[], int n) {
    printf("顶点\t距离\n");
    for (int i = 0; i < n; ++i) {
        printf("%d\t%d\n", i, dist[i]);
    }
}
// Bellman-Ford算法实现
bool bellmanFord(struct Edge edges[], int E, int V, int src) {
    int dist[V];
    // 初始化距离数组
    for (int i = 0; i < V; i++) {
        dist[i] = INT_MAX;
    }
    dist[src] = 0;
    // 对所有边进行V-1次松弛
    for (int i = 1; i <= V - 1; i++) {
        for (int j = 0; j < E; j++) {
            int u = edges[j].src;
            int v = edges[j].dest;
            int weight = edges[j].weight;
            if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
            }
        }
    }
    // 检查负权重环
    for (int i = 0; i < E; i++) {
        int u = edges[i].src;
        int v = edges[i].dest;
        int weight = edges[i].weight;
        if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) {
            printf("图中存在负权重环\n");
            return false;
        }
    }
    printArr(dist, V);
    return true;
}
int main() {
    struct Edge edges[] = {
        {0, 1, -1}, {0, 2, 4}, {1, 2, 3}, {1, 3, 2},
        {1, 4, 2}, {3, 2, 5}, {3, 1, 1}, {4, 3, -3}
    };
    int V = 5;
    int E = sizeof(edges) / sizeof(edges[0]);
    bellmanFord(edges, E, V, 0);
    return 0;
}

Floyd-Warshall算法(所有顶点对最短路径)

Floyd-Warshall算法用于计算图中所有顶点对之间的最短路径。

#include <stdio.h>
#include <limits.h>
#define V 4  // 顶点数量
// 打印距离矩阵
void printSolution(int dist[][V]) {
    printf("所有顶点对之间的最短距离:\n");
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            if (dist[i][j] == INT_MAX) {
                printf("INF\t");
            } else {
                printf("%d\t", dist[i][j]);
            }
        }
        printf("\n");
    }
}
// Floyd-Warshall算法实现
void floydWarshall(int graph[][V]) {
    int dist[V][V];
    // 初始化距离矩阵
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            dist[i][j] = graph[i][j];
        }
    }
    // 对每个顶点作为中间顶点进行计算
    for (int k = 0; k < V; k++) {
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX && 
                    dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
    printSolution(dist);
}
int main() {
    /* 示例图 */
    int graph[V][V] = {
        {0, 5, INT_MAX, 10},
        {INT_MAX, 0, 3, INT_MAX},
        {INT_MAX, INT_MAX, 0, 1},
        {INT_MAX, INT_MAX, INT_MAX, 0}
    };
    floydWarshall(graph);
    return 0;
}

算法选择建议

  1. Dijkstra算法

    c语言 shortestpath
    (图片来源网络,侵删)
    • 适用于非负权重的图
    • 时间复杂度:O(V²) 或 O(E + V log V)(使用优先队列)
    • 不能处理负权重
  2. Bellman-Ford算法

    • 可以处理负权重
    • 可以检测负权重环
    • 时间复杂度:O(VE)
    • 比Dijkstra慢,但适用范围更广
  3. Floyd-Warshall算法

    • 计算所有顶点对之间的最短路径
    • 时间复杂度:O(V³)
    • 可以处理负权重(但不能有负权重环)

根据具体问题的需求选择合适的算法,如果只需要单源最短路径且权重非负,Dijkstra是最佳选择;如果可能存在负权重,使用Bellman-Ford;如果需要所有顶点对的最短路径,使用Floyd-Warshall。

c语言 shortestpath
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
如何去除手机端织梦网站自动跳转app?
« 上一篇 2025-12-20
C语言setsockopt如何正确设置套接字选项?
下一篇 » 2025-12-20

相关文章

取消
微信二维码
支付宝二维码

目录[+]