图搜索算法详解

一、介绍

图搜索算法是一种用于在图数据结构中搜索特定节点或路径的算法。图搜索算法可以用于解决许多实际问题,例如路径规划、社交网络分析、最短路径查找等。

常见的图搜索算法包括深度优先搜索(DFS)和广度优先搜索(BFS)。

深度优先搜索(DFS)从图中的一个节点开始,沿着路径一直向前直到不能再继续前进,然后回溯到前一个节点,继续搜索其他未访问的节点。DFS通常使用递归实现。

广度优先搜索(BFS)从图的起始节点开始,首先访问起始节点的所有邻居节点,然后再依次访问邻居节点的邻居节点,以此类推,直到搜索到目标节点或者所有节点都被访问。BFS通常使用队列实现。

除了DFS和BFS,还有一些其他的图搜索算法,例如Dijkstra算法、A*算法、迪克斯塔拉算法等。这些算法根据不同的问题需求,选择不同的搜索策略和优化方法,以达到更高效的搜索结果。

需要注意的是,图搜索算法在搜索大规模图时可能会面临性能问题,因为算法的时间复杂度通常与节点和边的数量成正比。因此,在实际应用中,可以根据具体情况选择合适的算法和优化技术来提高搜索效率。

二、深度优先搜索

深度优先搜索(DFS)是一种经典的图搜索算法,它通过递归地探索图的每个分支直到无法继续为止,然后回溯并继续探索其他未访问的分支。

下面是深度优先搜索的详细步骤和示例代码:

步骤:

  1. 创建一个visited数组,用于记录每个节点是否已经被访问过。
  2. 选择一个起始节点作为搜索的起点。
  3. 将起始节点设置为已访问状态,并进行相关操作(例如打印节点值)。
  4. 对于起始节点的每个邻居节点,如果这些邻居节点还没有被访问过,则递归地对邻居节点进行深度优先搜索。
  5. 重复步骤4,直到所有节点都被访问过。

示例代码:

// 定义一个图的邻接表表示方法
class Graph {
    constructor() {
        this.adjList = new Map();
    }

    addVertex(vertex) {
        this.adjList.set(vertex, []);
    }

    addEdge(vertex1, vertex2) {
        this.adjList.get(vertex1).push(vertex2);
        this.adjList.get(vertex2).push(vertex1);
    }

    getNeighbors(vertex) {
        return this.adjList.get(vertex);
    }
}

// 深度优先搜索算法
function dfs(graph, startVertex, visited) {
    visited[startVertex] = true;
    console.log(startVertex);

    const neighbors = graph.getNeighbors(startVertex);

    for (let neighbor of neighbors) {
        if (!visited[neighbor]) {
            dfs(graph, neighbor, visited);
        }
    }
}

// 测试代码
const graph = new Graph();

// 添加图的顶点和边
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addVertex('F');

graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('B', 'D');
graph.addEdge('B', 'E');
graph.addEdge('C', 'F');

// 创建一个visited数组,初始值为false
const visited = {};

// 从节点A开始进行深度优先搜索
dfs(graph, 'A', visited);

运行以上示例代码,输出结果为:

A
B
D
E
C
F

以上是深度优先搜索算法的详解及代码示例。通过递归地访问每个节点的邻居节点,深度优先搜索可以遍历整个图的所有节点。

三、广度优先搜索

广度优先搜索(BFS)是一种经典的图搜索算法,它从起始节点开始逐层地探索图的每个节点,直到找到目标节点为止。BFS使用队列数据结构来保存当前层的所有节点,并依次将它们出队列并访问,然后将它们的邻居节点入队列。

下面是广度优先搜索的详细步骤和示例代码:

步骤:

  1. 创建一个visited数组,用于记录每个节点是否已经被访问过。
  2. 创建一个队列,并把起始节点入队列。
  3. 将起始节点设置为已访问状态,并进行相关操作(例如打印节点值)。
  4. 循环执行以下操作,直到队列为空:
    • 出队列并取出队首节点作为当前节点。
    • 对当前节点的每个邻居节点,如果这些节点还没有被访问过,则将其入队列,并设置为已访问状态。
    • 进行相关操作(例如打印节点值)。
  5. 重复步骤4,直到所有节点都被访问过。

示例代码:

// 定义一个图的邻接表表示方法
class Graph {
    constructor() {
        this.adjList = new Map();
    }

    addVertex(vertex) {
        this.adjList.set(vertex, []);
    }

    addEdge(vertex1, vertex2) {
        this.adjList.get(vertex1).push(vertex2);
        this.adjList.get(vertex2).push(vertex1);
    }

    getNeighbors(vertex) {
        return this.adjList.get(vertex);
    }
}

// 广度优先搜索算法
function bfs(graph, startVertex) {
    const visited = {};
    const queue = [];

    queue.push(startVertex);
    visited[startVertex] = true;

    while (queue.length > 0) {
        const currentVertex = queue.shift();
        console.log(currentVertex);

        const neighbors = graph.getNeighbors(currentVertex);

        for (let neighbor of neighbors) {
            if (!visited[neighbor]) {
                queue.push(neighbor);
                visited[neighbor] = true;
            }
        }
    }
}

// 测试代码
const graph = new Graph();

// 添加图的顶点和边
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addVertex('F');

graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('B', 'D');
graph.addEdge('B', 'E');
graph.addEdge('C', 'F');

// 从节点A开始进行广度优先搜索
bfs(graph, 'A');

运行以上示例代码,输出结果为:

A
B
C
D
E
F

以上是广度优先搜索算法的详解及代码示例。通过使用队列数据结构,广度优先搜索可以逐层地遍历整个图的所有节点。

四、Dijkstra算法

Dijkstra算法是一种图搜索算法,用于计算图中某一起点到其他顶点的最短路径。该算法的基本思想是通过逐步扩展路径的方式,不断更新起点到其他顶点的最短距离。

算法步骤如下:

  1. 初始化起点的最短距离为0,其他顶点的最短距离为无穷大。
  2. 创建一个集合S,用于存放已经找到最短路径的顶点。
  3. 当集合S中不包含所有顶点时,执行以下循环:
    • 从集合V-S中选择一个最短距离的顶点u,加入集合S。
    • 更新起点到集合V-S中顶点的最短距离,如果经过顶点u到达顶点v的路径比当前最短距离还要短,则更新最短距离。
  4. 循环结束后,最短路径就计算完成。

下面是Dijkstra算法的代码实现(使用Python语言):

def dijkstra(graph, start):
    # 初始化起点到其他顶点的最短距离
    distance = {vertex: float('inf') for vertex in graph}
    distance[start] = 0
    
    # 创建一个集合存放已经找到最短路径的顶点
    visited = set()
    
    while len(visited) < len(graph):
        # 选择一个最短距离的顶点加入集合
        min_distance = float('inf')
        for vertex in distance:
            if vertex not in visited and distance[vertex] < min_distance:
                min_distance = distance[vertex]
                current_vertex = vertex
                
        visited.add(current_vertex)
        
        # 更新最短距离
        for neighbor, weight in graph[current_vertex].items():
            if neighbor not in visited:
                new_distance = distance[current_vertex] + weight
                if new_distance < distance[neighbor]:
                    distance[neighbor] = new_distance
                    
    return distance

上述代码中,graph为图的邻接矩阵表示,start为起点顶点。distance是一个字典,用于存放起点到其他顶点的最短距离。

参考资料:

  • Dijkstra's algorithm: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm

五、A*算法

A*(A-Star)算法是一种启发式搜索算法,用于计算图中某一起点到目标顶点的最短路径。与Dijkstra算法不同,A*算法通过评估函数来估计从起点经过某一顶点到达目标顶点的代价,并用这个估计值来指导搜索过程。

算法步骤如下:

  1. 初始化起点的代价为0,其他顶点的代价为无穷大。
  2. 创建一个开放列表(open list)用于存放待探索的顶点。
  3. 将起点加入开放列表,并设置起点的代价为f = g + h,其中g为起点到当前顶点的实际代价,h为当前顶点到目标顶点的估计代价。
  4. 当开放列表不为空时,执行以下循环:
    • 从开放列表中选择一个具有最小f值的顶点作为当前顶点,并移出开放列表。
    • 如果当前顶点是目标顶点,则搜索结束,找到最短路径。
    • 否则,对当前顶点的所有邻居顶点进行以下操作:
      • 计算邻居顶点到起点的实际代价g' = g + w,其中w为当前顶点到邻居顶点的边权重。
      • 如果邻居顶点不在开放列表中,或者g'比邻居顶点的实际代价要小,则更新邻居顶点的代价g和f,并将邻居顶点加入开放列表。
  5. 如果开放列表为空,搜索结束,未找到最短路径。

下面是A*算法的代码实现(使用Python语言):

from heapq import heappop, heappush

def astar(graph, start, goal):
    # 初始化起点的代价为0,其他顶点的代价为无穷大
    g = {vertex: float('inf') for vertex in graph}
    g[start] = 0
    
    # 创建一个优先队列用于存放待探索的顶点
    open_list = []
    heappush(open_list, (0, start))
    
    while open_list:
        # 选择具有最小f值的顶点作为当前顶点
        _, current_vertex = heappop(open_list)
        
        # 如果当前顶点是目标顶点,则搜索结束,找到最短路径
        if current_vertex == goal:
            break
            
        # 遍历当前顶点的邻居顶点
        for neighbor, weight in graph[current_vertex].items():
            # 计算邻居顶点到起点的实际代价g'
            g_prime = g[current_vertex] + weight
            
            # 如果邻居顶点不在开放列表中,或者g'比邻居顶点的实际代价要小,则更新邻居顶点的代价和加入开放列表
            if g_prime < g[neighbor]:
                g[neighbor] = g_prime
                f = g_prime + heuristic(neighbor, goal)  # 使用启发函数计算估计代价
                heappush(open_list, (f, neighbor))
                
    return g[goal]

def heuristic(vertex, goal):
    # 启发函数,用于估计当前顶点到目标顶点的代价
    return 0  # 返回0表示不使用任何启发信息,即变为Dijkstra算法

上述代码中,graph为图的邻接矩阵表示,start为起点顶点,goal为目标顶点。g为一个字典,用于存放起点到各顶点的实际代价。

启发函数heuristic是A*算法中的关键,它用于估计当前顶点到目标顶点的代价。可以根据实际问题的特点设计启发函数,以提高搜索效率。

参考资料:

  • A* search algorithm: https://en.wikipedia.org/wiki/A*_search_algorithm

##欢迎关注交流,开发逆商潜力,提升个人反弹力:

 

  • 35
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

runqu

你的鼓励是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值