dijkstra算法求单源最短路径(C语言)
·
Dijkstra算法用于求解单源最短路径问题,即从一个起始节点到图中其他所有节点的最短路径
-
使用邻接矩阵: 邻接表在内存管理上更灵活,但会增加代码行数。邻接矩阵更简洁,但空间复杂度更高。对于小型图,这是可以接受的。
-
省略错误处理: 为了精简代码,我们省略了内存分配错误的检查。 实际应用中,这非常重要,但在教学示例中可以忽略。
-
简化输出: 只输出源点到其他节点的最短距离,不输出路径。
以下是一个简化的Dijkstra算法C代码,使用邻接矩阵,大约20行:
#include <stdio.h>
#include <limits.h>
#define INF INT_MAX
#define V 5 // 顶点数,需要修改
int main() {
int graph[V][V] = {
{0, 4, 1, INF, INF},
{4, 0, 2, 1, INF},
{1, 2, 0, 5, INF},
{INF, 1, 5, 0, 3},
{INF, INF, INF, 3, 0}
}; // 邻接矩阵表示图
int dist[V];
int visited[V] = {0};
int src = 0;
for (int i = 0; i < V; i++) dist[i] = INF;
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = -1;
for (int v = 0; v < V; v++)
if (!visited[v] && (u == -1 || dist[v] < dist[u])) u = v;
visited[u] = 1;
for (int v = 0; v < V; v++)
if (!visited[v] && graph[u][v] && dist[u] != INF && dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
for (int i = 0; i < V; i++)
printf("从 %d 到 %d 的最短距离:%d\n", src, i, dist[i] == INF ? -1 : dist[i]);
return 0;
}
注意: 这个简化版本有以下限制:
- 固定顶点数:
V定义了顶点数,需要手动修改。 - 硬编码图: 图的邻接矩阵直接写在了代码里,修改图需要修改代码。
- 无错误处理: 没有处理内存分配错误或图结构错误。
- 仅输出距离: 只输出最短距离,不输出路径。
它适用于边权重非负的图。对于更复杂的应用,建议使用更健壮的版本(下面提供的版本)。 这个简化版仅用于理解算法的核心思想。
#include <stdio.h>
#include <stdlib.h>
#include <limits.h> // 用于INT_MAX
#define INF INT_MAX // 定义无穷大
// 表示图中边的结构体
struct Edge {
int dest; // 目标节点
int weight; // 权重
};
// 表示图中节点的结构体
struct Node {
int vertex; // 节点编号
struct Edge* edges; // 指向边的数组
int edgeCount; // 边数
};
// 创建图的函数,numVertices为节点数,numEdges为边数
struct Node* createGraph(int numVertices, int numEdges) {
struct Node* graph = (struct Node*)malloc(sizeof(struct Node) * numVertices);
if (graph == NULL) {
perror("内存分配失败");
exit(1);
}
for (int i = 0; i < numVertices; i++) {
graph[i].vertex = i;
graph[i].edges = NULL;
graph[i].edgeCount = 0;
}
// 添加边 (需要根据你的图的表示方式修改这部分)
// 例如:添加从节点0到节点1,权重为4的边
// graph[0].edges = addEdge(graph[0].edges, &(graph[0].edgeCount), 1, 4);
// ... 添加其他边 ...
return graph;
}
//辅助函数,向节点添加一条边
struct Edge* addEdge(struct Edge* edges, int *edgeCount, int dest, int weight){
struct Edge* newEdges = (struct Edge*)realloc(edges, sizeof(struct Edge) * (*edgeCount + 1));
if(newEdges == NULL){
perror("内存分配失败");
exit(1);
}
newEdges[*edgeCount].dest = dest;
newEdges[*edgeCount].weight = weight;
(*edgeCount)++;
return newEdges;
}
// Dijkstra算法实现
void dijkstra(struct Node* graph, int numVertices, int source) {
int dist[numVertices]; // 从源节点到每个节点的距离
int visited[numVertices]; // 用于标记节点是否已访问
int minDistance;
int minVertex;
// 初始化距离和访问数组
for (int i = 0; i < numVertices; i++) {
dist[i] = INF;
visited[i] = 0;
}
dist[source] = 0; // 源节点到自身的距离为0
// 寻找所有节点的最短路径
for (int count = 0; count < numVertices - 1; count++) {
minDistance = INF;
minVertex = -1;
// 找到距离最短且未访问的节点
for (int v = 0; v < numVertices; v++) {
if (!visited[v] && dist[v] <= minDistance) {
minDistance = dist[v];
minVertex = v;
}
}
// 如果没有未访问的节点,则跳出循环
if (minVertex == -1) break;
// 将选定的节点标记为已访问
visited[minVertex] = 1;
// 更新相邻节点的距离
for (int i = 0; i < graph[minVertex].edgeCount; i++) {
int v = graph[minVertex].edges[i].dest;
int weight = graph[minVertex].edges[i].weight;
if (!visited[v] && dist[minVertex] != INF && dist[minVertex] + weight < dist[v]) {
dist[v] = dist[minVertex] + weight;
}
}
}
// 打印从源节点到其他节点的最短距离
printf("从节点 %d 到其他节点的最短距离:\n", source);
for (int i = 0; i < numVertices; i++) {
printf("节点 %d: %d\n", i, dist[i] == INF ? -1 : dist[i]); // -1表示不可达
}
}
int main() {
int numVertices = 5; // 例子:5个节点
int numEdges = 7; // 例子:7条边
// 创建图 (需要根据你的图的实际情况修改)
struct Node* graph = createGraph(numVertices, numEdges);
// 添加边 (例子,需要根据你的图的实际情况修改)
graph[0].edges = addEdge(graph[0].edges, &(graph[0].edgeCount), 1, 4);
graph[0].edges = addEdge(graph[0].edges, &(graph[0].edgeCount), 2, 1);
graph[1].edges = addEdge(graph[1].edges, &(graph[1].edgeCount), 3, 1);
graph[2].edges = addEdge(graph[2].edges, &(graph[2].edgeCount), 1, 2);
graph[2].edges = addEdge(graph[2].edges, &(graph[2].edgeCount), 3, 5);
graph[3].edges = addEdge(graph[3].edges, &(graph[3].edgeCount), 4, 3);
graph[4].edges = addEdge(graph[4].edges, &(graph[4].edgeCount), 3, 2);
int sourceVertex = 0; // 例子:源节点为0
dijkstra(graph, numVertices, sourceVertex);
//释放动态分配的内存,避免内存泄漏
for(int i=0; i<numVertices; ++i){
free(graph[i].edges);
}
free(graph);
return 0;
}
使用说明:
-
修改
createGraph函数和addEdge函数: 代码中createGraph函数和addEdge函数中的注释部分需要根据你图的实际结构进行修改。 你需要根据你的图的表示方法(邻接矩阵或邻接表)来修改代码。 此例子使用邻接表。 -
编译和运行: 使用C编译器(例如GCC)编译代码:
gcc dijkstra.c -o dijkstra,然后运行:./dijkstra
这段代码添加了更完善的内存错误检查和内存释放,避免了内存泄漏的问题。 请务必根据你自己的图的结构修改createGraph和添加边的部分。 本例使用邻接表表示图,你可以根据需要修改为邻接矩阵。
更多推荐
所有评论(0)