Python笔记07-BFS以及DFS学习笔记

前几天观看了B站up主:正月点灯笼 的视频,里面讲到了BFS和DFS的算法,这里我靠自己的理解还原其视频中的代码:

graph = {
    'A': ['B', 'C', 'D'],
    'B': ['A', 'C', 'E'],
    'C': ['A', 'B', 'E'],
    'D': ['A', 'E'],
    'E': ['B', 'C', 'D', 'F'],
    'F': ['E'],
}


def bfs(graph, s):
    queue = []  # 设置一个空队列
    queue.append(s)  # 放入第一个节点
    parent = {s: None}  # 设置一个父级字典,并初始化
    seen = set()  # 设置一个空集合,用于记录走过的点
    seen.add(s)  # 加入列队的同时记录该点
    while queue:
        vertex = queue.pop(0)  # 取出队列中的第一个元素
        nodes = graph[vertex]  # 获得该点的接通点
        for node in nodes:  # 遍历所有节点
            if node not in seen:  # 如果没有走过
                queue.append(node)  # 将节点放入队列
                parent[node] = vertex  # 记录该点的父节点
                seen.add(node)  # 加入的同时记录该点
                # print(vertex)
    return parent


def dfs(graph, s):
    queue = []  # 设置一个空栈
    queue.append(s)  # 放入第一个节点
    parent = {s: None}  # 设置一个父级字典,并初始化
    seen = set()  # 设置一个空集合,用于记录走过的点
    seen.add(s)  # 加入列队的同时记录该点
    while queue:
        vertex = queue.pop()  # 弹栈
        nodes = graph[vertex]  # 获得该点的接通点
        for node in nodes:  # 遍历所有节点
            if node not in seen:  # 如果没有走过
                queue.append(node)  # 将节点放入栈
                parent[node] = vertex  # 记录该点的父节点
                seen.add(node)  # 加入的同时记录该点
                # print(vertex)
    return parent


def show_path(graph, s, e, fs=bfs):
    parent = fs(graph, s)  # 遍历出所有路径
    par = e  # 设置终点
    path = []
    while par:
        path.append(par)  # 将终点加入路径列表
        par = parent[par]  # 求得终点的父节点,并且循环上一级
        # 起点的父节点为空,所以会中断循环
    path.reverse()  # 倒置列表
    result = '-->'.join(path)  # 包装结果
    print(result)  # 打印结果


show_path(graph, 'A', 'F', fs=bfs)
show_path(graph, 'A', 'F', fs=dfs)

以上是BFS和DFS的代码,这里写一下自己的理解。
BFS 首先是讲起点节点放入队列,然后取出,取出的同时放入该节点的子节点,然后依次取出子节点,取出的同时放入子子节点…直至队列为空。
DFS也一样,不过不同的是放入的不是队列而知栈。


在BFS的基础上可以实现最短路径的查找:

import heapq
import math

graph = {
    'A': {'B': 5, 'C': 1},
    'B': {'A': 5, 'D': 1, 'C': 2},
    'C': {'A': 1, 'B': 2, 'D': 4, 'E': 8},
    'D': {'B': 1, 'C': 4, 'E': 3, 'F': 6},
    'E': {'C': 8, 'D': 3},
    'F': {'D': 6},
}


def init_distance(graph, s):
    distance = {}
    for node in graph:
        if node == s:  # 起点到起点的距离为零
            distance[node] = 0
        else:  # 其他点到起点的距离为无穷
            distance[node] = math.inf
    return distance


def bfs(graph, s):
    queue = []  # 建立一个队列
    heapq.heappush(queue, (0, s))  # 放入队列
    seen = set()  # 建立一个空集,记录出现过的节点
    parent = {s: None}  # 建立一个字典,记录节点的父节点
    distance = init_distance(graph, s)  # 初始化到起点的距离
    while queue:
        pair = heapq.heappop(queue)  # 取出一个顶点(距离,节点)
        vertex = pair[1]  # 顶点
        dis_vertex = pair[0]  # 顶点到起点的距离
        seen.add(vertex)
        # 取出的时候记录,队列里面存在同一节点不同距离的情况
        # 所以唯有以取出的时候来判断
        nodes = graph[vertex]  # 取出节点{节点:距上一点距离}
        for node, dis_parent in nodes.items():
            if node not in seen:
                # 该点到起点的距离为
                # 其父节点到起点的距离+其到父节点的距离
                dis_start = dis_vertex + dis_parent
                if dis_start < distance[node]:
                    # 如果该点到起点的距离小于距离字典中的距离:
                    # 加入队列
                    heapq.heappush(queue, (dis_start, node))
                    # 记录距离
                    distance[node] = dis_start
                    # 记录父节点
                    parent[node] = vertex
    return parent, distance


def show_path(graph, s, e):
    parent, distance = bfs(graph, s)
    par = e
    path = []
    while par:
        path.append(par)#
        par = parent[par]
    path.reverse()
    per_node = path[0]
    result = per_node
    for node in path[1:]:
        result += '-' + str(graph[per_node][node]) + '->' + node
        per_node = node
    print(distance[e])
    print(result)


show_path(graph, 'A', 'F')

这里使用了优先队列,将距离起点近的节点排在前面优先取出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值