图搜索算法详解

图搜索算法是用于在图结构中寻找特定节点或路径的算法。图是由节点(或顶点)和边组成的集合,节点代表对象,边代表节点之间的连接。图搜索算法广泛应用于各种领域,比如网络路由、社交媒体分析、推荐系统等。 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哥关于图搜索算法的一些见解,分享给你,一起进步。

相关推荐
乌日尼乐3 分钟前
【Java基础整理】封装、继承、抽象、接口和多态
java·后端
heartbeat..5 分钟前
JavaWeb 入门 - HttpServletResponse 响应对象 详解
java·网络·http·web·response
zs宝来了6 分钟前
Spring Boot启动流程源码深度解析:电商订单系统面试实战
java·spring boot·面试·源码分析·电商
智航GIS6 分钟前
9.1 多线程入门
java·开发语言·python
我是谁的程序员7 分钟前
不用 Instruments 而在 Windows 环境下测试 iOS App
后端
ServBay8 分钟前
PHP 8.6 新特性预览,更简洁的语法与更严谨的类型控制
后端·php
文心快码BaiduComate11 分钟前
用Comate开发我的第一个MCP——让Vibe Coding长长脑子
前端·后端·程序员
神奇小汤圆14 分钟前
Spring Boot + 执行管道:让业务流程清晰可控
后端
消失的旧时光-194315 分钟前
从 Java 接口到 Dart freezed:一文彻底理解 Dart 的数据模型设计
java·开发语言·flutter·dart
就这个丶调调18 分钟前
Java ConcurrentHashMap源码深度解析:从底层原理到性能优化
java·并发编程·源码分析·线程安全·concurrenthashmap