面试题答案
一键面试实现思路
- 初始化:使用邻接矩阵表示图,初始化距离数组
dist
,将所有顶点的距离设为极大值,源点距离设为0。同时初始化一个集合visited
来记录已确定最短路径的顶点。 - 循环选择顶点:在未访问的顶点中选择距离源点最近的顶点
u
,标记为已访问。 - 更新距离:对于与
u
相邻的顶点v
,如果通过u
到达v
的距离比当前v
的距离更小,且不构成负权环(可以通过额外的检查机制,例如Bellman - Ford算法的思想,这里采用一个简单的限制负权边影响的方式),则更新v
的距离。 - 处理负权边:为了处理负权边,每次更新距离时,要检查是否因为负权边导致距离可以进一步减小。这里采用一个简单的方法,在更新距离后,再次遍历所有边,看是否能进一步优化距离,若能优化且未超过一定的迭代次数(防止陷入死循环,例如100次),则继续优化。
关键代码段
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define V 6 // 顶点数
// 找到距离源点最近且未访问的顶点
int minDistance(int dist[], int visited[]) {
int min = INT_MAX, minIndex;
for (int v = 0; v < V; v++)
if (!visited[v] && dist[v] <= min)
min = dist[v], minIndex = v;
return minIndex;
}
// 打印从源点到各顶点的最短路径
void printPath(int parent[], int j) {
if (parent[j] == -1)
return;
printPath(parent, parent[j]);
printf("%d ", j);
}
// 打印结果
void printSolution(int dist[], int parent[], int src) {
printf("Vertex\t Distance\tPath\n");
for (int i = 0; i < V; i++) {
printf("%d -> %d\t\t %d\t\t%d ", src, i, dist[i], src);
printPath(parent, i);
printf("\n");
}
}
// Dijkstra算法实现
void dijkstra(int graph[V][V], int src) {
int dist[V];
int visited[V];
int parent[V];
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, visited[i] = 0, parent[i] = -1;
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, visited);
visited[u] = 1;
for (int v = 0; v < V; v++)
if (!visited[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
parent[v] = u;
}
}
// 处理负权边
for (int k = 0; k < 100; k++) {
for (int u = 0; u < V; u++) {
for (int v = 0; v < V; v++) {
if (graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
parent[v] = u;
}
}
}
}
printSolution(dist, parent, src);
}
可以通过以下方式调用该函数:
int main() {
int graph[V][V] = {
{0, 4, 0, 0, 0, 0},
{4, 0, 8, 0, 0, 0},
{0, 8, 0, 7, 0, 4},
{0, 0, 7, 0, 9, 14},
{0, 0, 0, 9, 0, 10},
{0, 0, 4, 14, 10, 0}
};
dijkstra(graph, 0);
return 0;
}