图搜索算法是用于在图结构中寻找特定节点或路径的算法。图是由节点(或顶点)和边组成的集合,节点代表对象,边代表节点之间的连接。图搜索算法广泛应用于各种领域,比如网络路由、社交媒体分析、推荐系统等。 V哥最近总是在多个地方都看到关于图搜索算法的讨论,下面是一些常见的图搜索算法:
1. 深度优先搜索(DFS) 深度优先搜索是一种用于遍历或搜索树或图的算法。该算法会尽可能深地搜索图的分支。当节点v的所有边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这个过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
2. 广度优先搜索(BFS) 广度优先搜索是一种先遍历最近的节点,逐渐向外扩展的搜索算法。它从源节点开始,首先访问所有距离源节点为1的节点,然后访问所有距离源节点为2的节点,以此类推,直到访问到目标节点。广度优先搜索可以确保在找到最短路径时停止。
3. A搜索算法 A搜索算法是一种启发式搜索算法,它使用启发式函数来评估从源节点到目标节点的路径的成本。启发式函数是一种估计函数,它提供了从当前节点到目标节点的估计成本。A搜索算法在优先队列中根据f(n) = g(n) + h(n)的值来选择下一个要访问的节点,其中g(n)是从源节点到当前节点的实际成本,h(n)是当前节点到目标节点的估计成本。A搜索算法可以找到最短路径,但它的性能取决于启发式函数的选择。
4. Dijkstra算法 Dijkstra算法是一种用于在加权图中找到最短路径的算法。它从源节点开始,首先访问所有直接相邻的节点,然后访问所有距离源节点为2的节点,以此类推,直到访问到目标节点。与广度优先搜索不同,Dijkstra算法考虑了边的权重,因此它适用于加权图。
这些图搜索算法在计算机科学中非常重要,它们为解决各种问题提供了强大的工具。在实际应用中,选择合适的算法取决于具体问题的需求和图的结构特性。
以下是四种图搜索算法的详细介绍和Java代码实现案例。
1、深度优先搜索(DFS)
深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法。DFS沿着一个分支遍历,直到这个分支的末端,然后进行回溯。
Java代码实现:
java
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Graph {
private int V; // 顶点的数量
private List<List<Integer>> adj; // 邻接表
public Graph(int v) {
V = v;
adj = new ArrayList<>(v);
for (int i = 0; i < v; ++i) {
adj.add(new ArrayList<>());
}
}
public void addEdge(int v, int w) {
adj.get(v).add(w); // 添加边
}
public void DFS(int v) {
boolean[] visited = new boolean[V];
Stack<Integer> stack = new Stack<>();
stack.push(v);
visited[v] = true;
while (!stack.isEmpty()) {
int vertex = stack.pop();
System.out.print(vertex + " ");
List<Integer> neighbors = adj.get(vertex);
for (int neighbor : neighbors) {
if (!visited[neighbor]) {
stack.push(neighbor);
visited[neighbor] = true;
}
}
}
}
}
2、广度优先搜索(BFS)
广度优先搜索(BFS)是一种先遍历最近的节点,逐渐向外扩展的搜索算法。BFS从源节点开始,首先访问所有距离源节点为1的节点,然后访问所有距离源节点为2的节点,以此类推,直到访问到目标节点。
Java代码实现:
java
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Graph {
private int V; // 顶点的数量
private List<List<Integer>> adj; // 邻接表
public Graph(int v) {
V = v;
adj = new ArrayList<>(v);
for (int i = 0; i < v; ++i) {
adj.add(new ArrayList<>());
}
}
public void addEdge(int v, int w) {
adj.get(v).add(w); // 添加边
}
public void BFS(int v) {
boolean[] visited = new boolean[V];
Queue<Integer> queue = new LinkedList<>();
visited[v] = true;
queue.add(v);
while (!queue.isEmpty()) {
int vertex = queue.poll();
System.out.print(vertex + " ");
List<Integer> neighbors = adj.get(vertex);
for (int neighbor : neighbors) {
if (!visited[neighbor]) {
queue.add(neighbor);
visited[neighbor] = true;
}
}
}
}
}
3、A*
搜索算法
A*
搜索算法是一种启发式搜索算法,它使用启发式函数来评估从源节点到目标节点的路径的成本。A搜索算法在优先队列中根据f(n) = g(n) + h(n)的值来选择下一个要访问的节点,其中g(n)是从源节点到当前节点的实际成本,h(n)是当前节点到目标节点的估计成本。
Java代码实现:
java
import java.util.*;
public class AStarSearch {
class Node {
int id;
int g; // 从起始点到当前点的成本
int h; // 当前点到终点的估计成本
int f; // g + h
Node parent;
public Node(int id, int g, int h, Node parent) {
this.id = id;
this.g = g;
this.h = h;
this.f = g + h;
this.parent = parent;
}
}
public List<Integer> aStarSearch(int start, int goal, int[][] graph) {
PriorityQueue<Node> openList = new PriorityQueue<>(Comparator.comparingInt(node -> node.f));
HashSet<Integer> closedList = new HashSet<>();
Node startNode = new Node(start, 0, heuristic(start, goal), null);
openList.add(startNode);
while (!openList.isEmpty()) {
Node currentNode = openList.poll();
if (currentNode.id == goal) {
return getPath(currentNode);
}
closedList.add(currentNode.id);
for (int i = 0; i < graph[currentNode.id].length; i++) {
if (graph[currentNode.id][i] != 0) {
int neighborId = i;
if (closedList.contains(neighborId)) {
continue;
}
int tentativeG = currentNode.g + graph[currentNode.id][i];
if (!openList.contains(new Node(neighborId, 0,
if (!openList.contains(new Node(neighborId, 0, 0, null)) || tentativeG < openList.contains(new Node(neighborId, 0, 0, null)).g) {
openList.add(new Node(neighborId, tentativeG, heuristic(neighborId, goal), currentNode));
}
}
}
}
return null;
}
private List<Integer> getPath(Node node) {
List<Integer> path = new ArrayList<>();
while (node != null) {
path.add(0, node.id);
node = node.parent;
}
return path;
}
private int heuristic(int current, int goal) {
// 这里使用曼哈顿距离作为启发式函数
return Math.abs(current - goal);
}
}
4、Dijkstra算法
Dijkstra算法是一种用于在加权图中找到最短路径的算法。它从源节点开始,首先访问所有直接相邻的节点,然后访问所有距离源节点为2的节点,以此类推,直到访问到目标节点。与广度优先搜索不同,Dijkstra算法考虑了边的权重,因此它适用于加权图。
Java代码实现:
java
import java.util.*;
public class DijkstraAlgorithm {
public void dijkstra(int graph[][], int src) {
int V = graph.length;
int dist[] = new int[V]; // 存储最短路径的数组
Boolean sptSet[] = new Boolean[V]; // 标记节点是否被包括在最短路径树中
// 初始化所有距离为无穷大,sptSet全部为false
for (int i = 0; i < V; i++) {
dist[i] = Integer.MAX_VALUE;
sptSet[i] = false;
}
// 源节点到自己的距离为0
dist[src] = 0;
// 找到最短路径树中的所有节点
for (int count = 0; count < V - 1; count++) {
// 从未处理的节点中选择最小距离节点
int u = minDistance(dist, sptSet);
// 标记选中的节点为处理过
sptSet[u] = true;
// 更新与选中节点相邻的节点的距离
for (int v = 0; v < V; v++) {
if (!sptSet[v] && graph[u][v] != 0 && dist[u] != Integer.MAX_VALUE && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
// 打印最短路径数组
printSolution(dist, V);
}
// 一个用来找到最小距离节点的函数
private int minDistance(int dist[], Boolean sptSet[]) {
int min = Integer.MAX_VALUE, minIndex = -1;
for (int v = 0; v < dist.length; v++) {
if (!sptSet[v] && dist[v] <= min) {
min = dist[v];
minIndex = v;
}
}
return minIndex;
}
// 打印构造的最短路径树
private void printSolution(int dist[], int n) {
System.out.println("节点 \t\t 最短距离");
for (int i = 0; i < n; i++) {
System.out.println(i + " \t\t " + dist[i]);
}
}
public static void main(String[] args) {
DijkstraAlgorithm dijkstra = new DijkstraAlgorithm();
int graph[][] = new int[][] {
{0, 4, 0, 0, 0, 0, 0, 8, 0},
{4, 0, 8, 0, 0, 0, 0, 11, 0},
{0, 8, 0, 7, 0, 4, 0, 0, 2},
{0, 0, 7, 0, 9, 14, 0, 0, 0},
{0, 0, 0, 9, 0, 10, 0, 0, 0},
{0, 0, 4, 14, 10, 0, 2, 0, 0},
{0, 0, 0, 0, 0, 2, 0, 1, 6},
{8, 11, 0, 0, 0, 0, 1, 0, 7},
{0, 0, 2, 0, 0, 0, 6, 7, 0}
};
dijkstra.dijkstra(graph, 0);
}
}
以上是四种图搜索算法的Java实现。每种算法都有其特定的应用场景:
- DFS适用于探索所有可能的分支,例如游戏中的棋盘搜索、编译器中的语法分析等。
- BFS适用于寻找最短路径,特别是在无权图中。
A*
搜索算法适用于在有权图中寻找最短路径,特别是当图较大且目标节点较远时。- Dijkstra算法适用于在有权图中寻找最短路径,但不适用于有负权边的图。
在实际应用中,选择合适的算法取决于具体问题的需求和图的结构特性。这里 V哥必须要强调一下,如果图很大且目标节点很远,A*
搜索算法可能是更好的选择,因为它使用启发式函数来指导搜索,从而减少搜索空间。如果图是无权的,或者权重相同,BFS将是一个简单且有效的选择。DFS则适用于需要探索所有可能性的情况。好了,以上就是 V哥关于图搜索算法的一些见解,分享给你,一起进步。