👋 Hi, I’m @Beast Cheng
👀 I’m interested in photography, hiking, landscape…
🌱 I’m currently learning python, javascript, kotlin…
📫 How to reach me --> 458290771@qq.com
喜欢《数据结构》部分笔记的小伙伴可以订阅专栏,今后还会不断更新。🧑💻
感兴趣的小伙伴可以点一下订阅、收藏、关注!🚀
谢谢大家!🙏
单源最短路径
BFS算法(无权图)
代码实现
bool visited[MAX_VERTEX_NUM]; // 访问标记数组
// 广度优先遍历
void BFS (Graph G, int v) // 从顶点v出发,广度优先遍历图G
{
visit(v); // 访问初始顶点v
visited[v] = TRUE; // 对v做已访问标记
EnQueue(Q, v); // 顶点v入队列Q
while (!isEmpty(Q))
{
DeQueue(Q, v);
for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w))
{
if (!visited[w])
{
visit(w);
visited[w] = TRUE;
EnQueue(Q, w); // 顶点w入队列
}
}
}
}
对代码进行改造
// 求顶点u到其他顶点的最短路径
void BFS_MIN_Distance(Graph G, int u)
{
// d[i]表示从u到i结点的最短路径
for(i = 0; i < G.vexnum; ++i)
{
d[i] = ∞; // 初始化路径长度
path[i] = -1; // 最短路径从哪个顶点过来
}
d[u] = 0;
visited[u] = TRUE;
EnQueue(Q, u);
while(!isEmpty(Q)) // BFS算法主过程
{
DeQueue(Q, u); // 队头元素u出队
for(w = FirstNeighbor(G, u); w >= 0; w = NextNeighbor(G, u, w))
{
if(!visited[w]) // w为u的尚未访问的邻接结点
{
d[w] = d[u] + 1; // 路径长度+1
path[w] = u; // 最短路径应从u到w
visited[w] = TRUE; // 设已访问标记
EnQueue(Q, w); // 顶点w入队
}
}
}
}
本质上是对BFS的修改,在 visit
一个顶点时,修改其最短路径长度 d[]
并在 path[]
记录前驱结点
Dijkstra算法(带权图、无权图)
初始:从
V
0
V_0
V0 开始,初始化三个数组信息,一开始先把
V
0
V_0
V0 设为 TRUE
,然后记录的是各个顶点到
V
0
V_0
V0 的最短路径长度
第一轮:循环遍历所有节点,找到还没有确定的阻断路径,且 dist
最小的顶点
V
i
V_i
Vi ,令 final[i] = true
第二轮:循环遍历所有节点,找到还没有确定的阻断路径,且 dist
最小的顶点
V
i
V_i
Vi ,令 final[i] = true
检查所有邻接自
V
i
V_i
Vi 的顶点,若其 final
值为 false
,则更新 dist
和 path
信息
第三轮:循环遍历所有节点,找到还没有确定的阻断路径,且 dist
最小的顶点
V
i
V_i
Vi ,令 final[i] = true
检查所有邻接自
V
i
V_i
Vi 的顶点,若其 final
值为 false
,则更新 dist
和 path
信息
时间复杂度: O ( ∣ V ∣ 2 ) O(|V|^2) O(∣V∣2)
用于负权值带权图
Dijkstra
算法可能失效
各顶点间最短路径
Floyd算法(带权图、无权图)
使用动态规划思想,将问题分为多个阶段
对于n个顶点的图G,求任意一对顶点 V i V_i Vi -> V j V_j Vj 之间的最短路径可分为如下几个阶段:
- 初始:不允许在其他顶点中转,最短路径是?
- 0:若允许在
V
0
V_0
V0 中转,最短路径是?
- 求 A ( 0 ) A^{(0)} A(0) 和 p a t h ( 0 ) path^{(0)} path(0)
- 1:若允许在
V
0
,
V
1
V_0,V_1
V0,V1 中转,最短路径是?
- 求 A ( 1 ) A^{(1)} A(1) 和 p a t h ( 1 ) path^{(1)} path(1)
- 2:若允许在
V
0
,
V
1
,
V
2
V_0,V_1,V_2
V0,V1,V2 中转,最短路径是?
- 求 A ( 2 ) A^{(2)} A(2) 和 p a t h ( 2 ) path^{(2)} path(2)
- ……
- n-1:若允许在 V 0 , V 1 , V 2 , . . . , V n − 1 V_0,V_1,V_2,...,V_{n-1} V0,V1,V2,...,Vn−1 中转,最短路径是?
Floyd算法核心代码
// ...准备工作,根据图的信息初始化矩阵 A 和 path
for(int k = 0; k < n; k ++){ // 考虑以 vk 作为中转点
for(int i = 0; i < n; i ++){ // 遍历整个矩阵,i 为行号,j 为列号
for(int j = 0; j < n; j ++){
if(A[i][j] > A[i][k] + A[k][j]){ // 以 vk 为中转点的路径更短
A[i][j] = A[i][k] + A[k][j]; // 更新最短路径长度
path[i][j] = k; // 中转点
}
}
}
}
时间复杂度:
O
(
∣
V
∣
3
)
O(|V|^3)
O(∣V∣3)
空间复杂度:
O
(
∣
V
∣
2
)
O(|V|^2)
O(∣V∣2)
Floyd
算法可以用于负权图
但是也有Floyd
算法不能解决的问题
Floyd
算法不能结局带有“负权回路”的图,这种图有可能没有最短路径