Dijkstra算法和广度优先搜索(BFS)算法是图论中常用的两种算法,它们用于解决不同类型的问题。本文将详细介绍这两种算法的原理、执行步骤、区别及应用场景,并提供代码实现。
Dijkstra算法
原理
Dijkstra算法是一种用于求解带权图中单源最短路径问题的算法。它基于贪心思想,即每一步选择当前最短的路径,并逐步扩展到其他节点。Dijkstra算法的核心思想是:每次选择未访问的顶点中距离起点最近的一个,然后用这个顶点更新其他顶点的距离。
执行步骤
- 初始化:
- 从起始顶点到自身的距离设为0,其他顶点的距离设为无穷大。
- 将所有顶点标记为未访问。
- 选择最小距离顶点:
- 从未访问的顶点中选择距离起始顶点最近的顶点,并标记为已访问。
- 更新距离:
- 对于该顶点的每一个邻接顶点,如果通过该顶点的路径比之前记录的距离更短,则更新该邻接顶点的距离。
- 重复步骤2和3,直到所有顶点都被访问。
代码实现
Dijkstra算法的Kotlin实现:
import java.util.PriorityQueue
data class Edge(val target: String, val weight: Int)
data class Vertex(val name: String, val distance: Int) : Comparable<Vertex> {
override fun compareTo(other: Vertex): Int = distance.compareTo(other.distance)
}
fun dijkstra(graph: Map<String, List<Edge>>, start: String): Map<String, Int> {
//distances用于存储从起始节点到其他节点的最短距离,
//初始时将所有距离设为Int.MAX_VALUE,起始节点的距离为0
val distances = mutableMapOf<String, Int>().apply {
graph.keys.forEach { put(it, Int.MAX_VALUE) }
put(start, 0)
}
//使用PriorityQueue来选择当前距离最小的顶点。
//PriorityQueue通过自定义Comparable接口的实现来进行优先级排序。
val priorityQueue = PriorityQueue<Vertex>().apply { add(Vertex(start, 0)) }
//当队列不为空时,取出队列中的顶点
while (priorityQueue.isNotEmpty()) {
val (currentVertex, currentDistance) = priorityQueue.poll()
if (currentDistance > distances[currentVertex]!!) continue
//更新其邻接点的距离
//如果有更短的路径则更新distances
for (edge in graph[currentVertex] ?: emptyList()) {
val newDistance = currentDistance + edge.weight
if (newDistance < distances[edge.target]!!) {
distances[edge.target] = newDistance
priorityQueue.add(Vertex(edge.target, newDistance))
}
}
}
return distances
}
BFS(广度优先搜索)算法
原理
广度优先搜索是一种遍历图的算法,用于找到从起始顶点到其他顶点的最短路径(在无权图中)。BFS使用队列数据结构来按层次遍历图的节点,即首先访问起始节点的所有邻接节点,然后依次访问这些邻接节点的邻接节点,依此类推。
执行步骤
- 初始化:
- 创建一个空队列,将起始节点加入队列。
- 标记起始节点为已访问。
- 出队列:
- 从队列中取出一个节点,记为当前节点。
- 访问邻接节点:
对于当前节点的每一个邻接节点,如果它们尚未被访问,则将其加入队列并标记为已访问。 4. 重复步骤2和3,直到队列为空。
代码实现
BFS算法的Kotlin实现:
import java.util.ArrayDeque
fun bfs(graph: Map<String, List<String>>, start: String): List<String> {
//visited集合用于跟踪已访问的节点,避免重复访问
val visited = mutableSetOf<String>()
//使用ArrayDeque来实现队列功能
val queue = ArrayDeque<String>()
//order列表记录访问节点的顺序
val order = mutableListOf<String>()
visited.add(start)
queue.add(start)
while (queue.isNotEmpty()) {
val vertex = queue.removeFirst()
order.add(vertex)
for (neighbor in graph[vertex] ?: emptyList()) {
if (neighbor !in visited) {
visited.add(neighbor)
queue.add(neighbor)
}
}
}
return order
}
区别及应用场景
区别
- 适用图类型:
- Dijkstra算法适用于带权图,要求所有边的权值非负。
- BFS适用于无权图或权值相同的图。
- 复杂度:
- Dijkstra算法的时间复杂度为O(V^2)(使用矩阵表示图)或O(E + V log V)(使用优先队列),其中V是顶点数,E是边数。
- BFS的时间复杂度为O(V + E),其中V是顶点数,E是边数。
- 结果:
- Dijkstra算法返回起始节点到其他所有节点的最短路径。
- BFS返回从起始节点按层次遍历的顺序。
应用场景
- Dijkstra算法:
- 用于解决带权图中的最短路径问题,例如交通网络中最短路线规划、网络路由等。
- BFS算法:
- 用于无权图中最短路径的寻找,如社交网络中找到最短关系链、迷宫最短路径等。
这两种算法在各自的应用领域都有广泛的应用。Dijkstra算法适用于有权图的情况,而BFS则是解决无权图问题的常用方法。