元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
算法基础
▶
复杂度分析
时间复杂度
空间复杂度
渐进符号
▶
算法思想
分治法
贪心算法
回溯法
概率算法
枚举算法
递推算法
递归算法
动态规划
分支限界法
模拟算法
▶
算法分析
正确性证明
性能优化
算法比较
▶
搜索算法
▶
基本搜索
顺序搜索
二分搜索
插值搜索
▶
图搜索
深度优先搜索
广度优先搜索
启发式搜索
▶
高级搜索
双向搜索
A*算法
模式匹配
▶
排序算法
▶
比较类排序
冒泡排序
快速排序
归并排序
插入排序
选择排序
▶
非比较类排序
计数排序
基数排序
桶排序
▶
高级排序
堆排序
希尔排序
外部排序
拓扑排序
▶
图论算法
▶
图的表示
邻接矩阵
邻接表
边集数组
▶
最短路径
Dijkstra算法
Floyd算法
Bellman-Ford算法
最短路径概述
▶
生成树
Prim算法
Kruskal算法
并查集
最小生成树
▶
图的连通性
强连通分量
割点与桥
双连通分量
欧拉路径
▶
动态规划
▶
基础概念
最优子结构
重叠子问题
状态转移方程
▶
经典问题
背包问题
最长公共子序列
编辑距离
▶
优化技巧
空间优化
状态压缩
区间动态规划
▶
字符串算法
▶
字符串匹配
KMP算法
Boyer-Moore算法
Sunday算法
▶
字符串处理
字典树
后缀数组
字符串哈希
▶
压缩算法
游程编码
Huffman编码
LZ77算法
发布时间:
2025-03-21 19:21
↑
☰
# Floyd算法 Floyd算法(Floyd-Warshall算法)是一种用于寻找加权图中所有顶点对之间最短路径的动态规划算法。本文将详细介绍Floyd算法的原理、实现和应用。 ## 基本概念 ### 多源最短路径问题 与Dijkstra算法解决单源最短路径不同,Floyd算法可以在一次执行中找出所有顶点对之间的最短路径。这对于需要频繁查询任意两点间最短路径的场景特别有用。 ### 算法适用条件 1. 可处理有向图或无向图 2. 可以处理负权边(但不能有负权回路) 3. 适合稠密图 4. 图中顶点数量较小(通常小于1000) ## 算法原理 ### 核心思想 Floyd算法基于动态规划,通过逐步尝试是否可以通过中间顶点来优化当前已知的最短路径。对于顶点i和j之间的路径,算法会考虑是否存在顶点k,使得从i经过k到j的路径比已知的从i到j的直接路径更短。 ### 算法步骤 1. 初始化: - 对于直接相连的顶点,设置实际边权 - 对于不相连的顶点,设置距离为无穷大 - 对角线元素(自己到自己)设置为0 2. 对于每个顶点k作为中间点: - 对于每对顶点(i,j) - 如果dist[i][k] + dist[k][j] < dist[i][j] - 则更新dist[i][j] = dist[i][k] + dist[k][j] ## 代码实现 ### 基本实现 ```go type Graph struct { vertices int dist [][]int next [][]int // 用于路径重建 } func NewGraph(v int) *Graph { // 初始化图 dist := make([][]int, v) next := make([][]int, v) for i := range dist { dist[i] = make([]int, v) next[i] = make([]int, v) for j := range dist[i] { if i != j { dist[i][j] = math.MaxInt32 } next[i][j] = j // 初始化路径 } } return &Graph{ vertices: v, dist: dist, next: next, } } func (g *Graph) AddEdge(from, to, weight int) { g.dist[from][to] = weight } func (g *Graph) Floyd() { // Floyd-Warshall算法实现 for k := 0; k < g.vertices; k++ { for i := 0; i < g.vertices; i++ { for j := 0; j < g.vertices; j++ { if g.dist[i][k] != math.MaxInt32 && g.dist[k][j] != math.MaxInt32 { newDist := g.dist[i][k] + g.dist[k][j] if newDist < g.dist[i][j] { g.dist[i][j] = newDist g.next[i][j] = g.next[i][k] // 更新路径 } } } } } // 检测负权回路 for i := 0; i < g.vertices; i++ { if g.dist[i][i] < 0 { panic("图中存在负权回路") } } } func (g *Graph) GetPath(from, to int) []int { // 重建路径 if g.dist[from][to] == math.MaxInt32 { return nil // 不存在路径 } path := []int{from} for from != to { from = g.next[from][to] path = append(path, from) } return path } ``` ### 优化实现 ```go type Graph struct { vertices int dist [][]int next [][]int // 使用邻接表存储原始图结构 adj []map[int]int } func NewGraph(v int) *Graph { adj := make([]map[int]int, v) for i := range adj { adj[i] = make(map[int]int) } return &Graph{ vertices: v, adj: adj, } } func (g *Graph) AddEdge(from, to, weight int) { g.adj[from][to] = weight } func (g *Graph) InitializeFloyd() { // 延迟初始化距离矩阵 g.dist = make([][]int, g.vertices) g.next = make([][]int, g.vertices) for i := range g.dist { g.dist[i] = make([]int, g.vertices) g.next[i] = make([]int, g.vertices) for j := range g.dist[i] { if i == j { g.dist[i][j] = 0 } else if weight, ok := g.adj[i][j]; ok { g.dist[i][j] = weight } else { g.dist[i][j] = math.MaxInt32 } g.next[i][j] = j } } } ``` ## 应用示例 ### 网络路由 ```go type Router struct { id int name string capacity int } type Network struct { routers []Router graph *Graph } func NewNetwork(routers []Router) *Network { n := len(routers) network := &Network{ routers: routers, graph: NewGraph(n), } // 构建网络拓扑 for i := 0; i < n; i++ { for j := 0; j < n; j++ { if i != j { // 根据路由器容量和距离计算链路权重 weight := calculateLinkWeight(routers[i], routers[j]) if weight > 0 { network.graph.AddEdge(i, j, weight) } } } } return network } func (n *Network) FindAllPaths() map[string][]Router { n.graph.InitializeFloyd() n.graph.Floyd() paths := make(map[string][]Router) for i := 0; i < len(n.routers); i++ { for j := 0; j < len(n.routers); j++ { if i != j { path := n.graph.GetPath(i, j) if path != nil { key := fmt.Sprintf("%s->%s", n.routers[i].name, n.routers[j].name) routerPath := make([]Router, len(path)) for k, idx := range path { routerPath[k] = n.routers[idx] } paths[key] = routerPath } } } } return paths } ``` ### 地图导航 ```go type Location struct { id int name string x, y float64 traffic float64 // 交通系数 } type NavigationSystem struct { locations []Location graph *Graph } func (ns *NavigationSystem) UpdateTraffic(locationID int, traffic float64) { // 更新交通状况并重新计算最短路径 ns.locations[locationID].traffic = traffic ns.rebuildGraph() ns.graph.InitializeFloyd() ns.graph.Floyd() } func (ns *NavigationSystem) FindAllRoutes() map[string]struct { distance float64 path []string } { routes := make(map[string]struct { distance float64 path []string }) for i := 0; i < len(ns.locations); i++ { for j := 0; j < len(ns.locations); j++ { if i != j { path := ns.graph.GetPath(i, j) if path != nil { key := fmt.Sprintf("%s->%s", ns.locations[i].name, ns.locations[j].name) pathNames := make([]string, len(path)) for k, idx := range path { pathNames[k] = ns.locations[idx].name } routes[key] = struct { distance float64 path []string }{ distance: float64(ns.graph.dist[i][j]), path: pathNames, } } } } } return routes } ``` ## 性能分析 ### 时间复杂度 1. 基本实现: - 三重循环:O(V³) - 路径重建:O(V) - 总体复杂度:O(V³) 2. 空间优化: - 邻接表存储:O(V + E) - 距离矩阵:O(V²) - 总体复杂度:O(V²) ### 算法比较 1. Floyd vs Dijkstra: - Floyd适合求所有顶点对最短路径 - Dijkstra适合求单源最短路径 - Floyd可以处理负权边 - Dijkstra在稀疏图中更高效 2. 优化方向: - 使用并行计算加速 - 利用图的特殊结构 - 增量更新优化 ## 总结 1. 算法特点: - 实现简单直观 - 可处理负权边 - 一次计算全局最短路径 2. 使用建议: - 适合顶点数较少的稠密图 - 需要频繁查询任意两点间最短路径 - 图的结构相对稳定 3. 实际应用: - 网络路由计算 - 交通导航系统 - 社交网络分析 - 物流配送优化