终于搞懂Dijkstra算法了


Dijkstra算法用来解决单源最短路径问题,思路如下

将图中顶点分为2部分
S:已经找到最短路径的顶点
U:剩下的顶点
假设初始顶点为v0, 那么S:{v0}, U:{剩下的顶点}
从U中找到一个距离v0最近的一个顶点,假设为x,将x从U中移动到S。
对于U中的任意顶点y,如果d[v0][x] + d[x][y] < d[v0][y], 则d[v0][y] = d[v0][x] + d[x][y]。
如此循环,直到处理完U中所有顶点。

Dijkstra是按照路径长度递增的顺序,来求解v0到其他顶点的所有最短路径。
是一个贪心算法。

示例1

代码

// g[i][j]:顶点i、顶点j之间的距离
// 如果i、j直连,就是边ij的长度,
// 否则对应math.MaxInt32【i == j 时,也是math.MaxInt32】

// 返回 顶点 start 到 其他顶点 的最短距离
func shortestPath(g [][]int, start int) []int {
	// 顶点个数
	n := len(g)
	// 存储 顶点 start 到 其他顶点 的最短距离
	distance := make([]int, n)
	// start -> start的距离为0
	distance[start] = 0
	// 标记顶点的访问状态
	visited := make([]bool, n)
	// 顶点 start 加入到 S
	visited[start] = true
	// 确定剩下 n-1 个 顶点 的最短距离
	for i := 1; i < n; i++ {
		// 在 U 中找到最短路径对应的顶点
		// 需要比边的最大值要大
		min := math.MaxInt32 + 1
		var k int
		for j := 0; j < n; j++ {
			if !visited[j] && g[start][j] < min {
				min = g[start][j]
				k = j
			}
		}
		// 顶点 k 加入到 S
		visited[k] = true
		distance[k] = min
		// 更新 U 中的路径
		for j := 0; j < n; j++ {
			if !visited[j] && min+g[k][j] < g[start][j] {
				g[start][j] = min + g[k][j]
			}
		}
	}
	return distance
}

1个示例
在这里插入图片描述
输入

func Test_xx(t *testing.T) {
	g := [][]int{
		{math.MaxInt32, 4, math.MaxInt32, 2, math.MaxInt32},
		{4, math.MaxInt32, 4, 1, math.MaxInt32},
		{math.MaxInt32, 4, math.MaxInt32, 1, 3},
		{2, 1, 1, math.MaxInt32, 7},
		{math.MaxInt32, math.MaxInt32, 3, 7, math.MaxInt32},
	}
	fmt.Println(shortestPath(g, 0))
}

输出

[0 3 3 2 6]

再给一个示例
在这里插入图片描述
输入

func Test_xx(t *testing.T) {
	g := [][]int{
		{math.MaxInt32, math.MaxInt32, 10, math.MaxInt32, 30, 100},
		{math.MaxInt32, math.MaxInt32, 5, math.MaxInt32, math.MaxInt32, math.MaxInt32},
		{math.MaxInt32, math.MaxInt32, math.MaxInt32, 50, math.MaxInt32, math.MaxInt32},
		{math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, 10},
		{math.MaxInt32, math.MaxInt32, math.MaxInt32, 20, math.MaxInt32, 60},
		{math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32},
	}
	fmt.Println(shortestPath(g, 0))
}

输出

[0 2147483647 10 50 30 60]

上述代码会修改输入g,下面给一个不修改g的版本

示例2

func shortestPath2(g [][]int, start int) []int {
	n := len(g)
	distance := make([]int, n)
	for i := 0; i < n; i++ {
		distance[i] = g[start][i]
	}
	distance[start] = 0
	visited := make([]bool, n)
	visited[start] = true
	for i := 1; i < n; i++ {
		min := math.MaxInt32 + 1
		var k int
		for j := 0; j < n; j++ {
			if !visited[j] && distance[j] < min {
				min = distance[j]
				k = j
			}
		}
		visited[k] = true
		for j := 0; j < n; j++ {
			if !visited[j] && min+g[k][j] < distance[j] {
				distance[j] = min + g[k][j]
			}
		}
	}
	return distance
}

参考资料

https://houbb.github.io/2020/01/23/data-struct-learn-03-graph-dijkstra

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值