/** * Uses BFS to compute shortest paths in an unweighted graph. * * Args: * graph: Adjacency matrix. graph->arcs[u][v] != 0 means u is adjacent to v. * source: The source vertex index. * dist: Output array. dist[v] is the shortest edge count from source to v. * prev: Output array. prev[v] is the predecessor of v on the shortest path. */ voidBfsShortestPath(const MGraph *graph, int source, int dist[], int prev[]) { bool visited[MAX_VERTEX_NUM] = {false}; Queue queue; InitQueue(&queue);
for (int v = 0; v < graph->vexNum; ++v) { dist[v] = INF; prev[v] = -1; }
typedefstruct { int vexNum; int edgeNum; int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; } MGraph;
/** * Uses Dijkstra to compute shortest paths from one source. * * Args: * graph: Weighted adjacency matrix. INF means no edge. * source: The source vertex index. * dist: Output array. dist[v] is the shortest distance from source to v. * prev: Output array. prev[v] is the predecessor of v on the shortest path. * * Notes: * This algorithm requires all edge weights to be non-negative. */ voidDijkstra(const MGraph *graph, int source, int dist[], int prev[]) { bool final[MAX_VERTEX_NUM] = {false};
for (int v = 0; v < graph->vexNum; ++v) { dist[v] = graph->arcs[source][v];
if (graph->arcs[source][v] < INF && v != source) { prev[v] = source; } else { prev[v] = -1; } }
for (int round = 1; round < graph->vexNum; ++round) { int minDist = INF; int selected = -1;
/* Pick the unsettled vertex with the smallest current distance. */ for (int v = 0; v < graph->vexNum; ++v) { if (!final[v] && dist[v] < minDist) { minDist = dist[v]; selected = v; } }
if (selected == -1) { break; }
final[selected] = true;
/* Relax all outgoing edges of the selected vertex. */ for (int v = 0; v < graph->vexNum; ++v) { if (final[v] || graph->arcs[selected][v] == INF) { continue; }
/** * Uses Floyd-Warshall to compute all-pairs shortest paths. * * Args: * vertexCount: Number of vertices. * dist: Input and output matrix. dist[i][j] is the shortest distance i -> j. * path: Output matrix. path[i][j] stores an intermediate vertex, or -1. * * Notes: * dist[i][i] should be initialized to 0. * dist[i][j] should be initialized to INF when there is no edge i -> j. */ voidFloyd(int vertexCount, int dist[MAX_VERTEX_NUM][MAX_VERTEX_NUM], int path[MAX_VERTEX_NUM][MAX_VERTEX_NUM]) { for (int i = 0; i < vertexCount; ++i) { for (int j = 0; j < vertexCount; ++j) { path[i][j] = -1; } } // Floyd的核心就是这三层循环 for (int k = 0; k < vertexCount; ++k) { // 之前轮次允许0~k-1作为中转站,这一轮新加入k for (int i = 0; i < vertexCount; ++i) { for (int j = 0; j < vertexCount; ++j) { if (dist[i][k] == INF || dist[k][j] == INF) { continue; } // k作为新的中转站可以使得i-j距离进一步减少 if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; path[i][j] = k; } } } } }
/** * Prints intermediate vertices on the shortest path from start to end. * * Args: * path: Floyd path matrix. * start: Start vertex. * end: End vertex. */ voidPrintFloydPath(int path[MAX_VERTEX_NUM][MAX_VERTEX_NUM], int start, int end) { int middle = path[start][end];
/** * Uses SPFA to compute shortest paths from one source. * * Args: * graph: Directed weighted adjacency list. * source: The source vertex index. * dist: Output array. dist[v] is the shortest distance from source to v. * prev: Output array. prev[v] is the predecessor of v on the shortest path. * * Returns: * true if no negative cycle is found from source. * false if a negative cycle is reachable from source. */ boolSpfa(const ALGraph *graph, int source, int dist[], int prev[]) { bool inQueue[MAX_VERTEX_NUM] = {false}; int enqueueCount[MAX_VERTEX_NUM] = {0}; Queue queue; InitQueue(&queue);
for (int v = 0; v < graph->vexNum; ++v) { dist[v] = INF; prev[v] = -1; }
while (!IsQueueEmpty(&queue)) { int current = DeQueue(&queue); inQueue[current] = false;
for (int edgeIndex = graph->head[current]; edgeIndex != -1; edgeIndex = graph->edges[edgeIndex].next) { int next = graph->edges[edgeIndex].to; int weight = graph->edges[edgeIndex].weight;