算法宗门---广度有优先搜索BFS

广度优先搜索(BFS,Breadth-First Search)

一、BFS 的 "生活化故事":像找迷宫出口一样 "层层扩散"

你可以把 BFS 想象成 "小时候玩迷宫的最稳妥办法":假设你站在迷宫的起点,想找到出口,但你分不清哪条路是对的。这时你不会一头扎进某条路死磕(那是深度优先搜索 DFS),而是先把离你一步之遥的所有路口 都标记出来(这些是 "第一层");然后从这些第一层路口出发,再把离它们一步之遥、且没被标记过的路口 标记出来("第二层");以此类推,直到某一层的人喊 "我找到出口了!"------ 这就是 BFS 的核心逻辑:层层递进、地毯式搜索

从学术角度说,BFS 的雏形最早出现在 19 世纪数学家康托尔、若尔当对图结构的研究中,后来被系统应用到计算机领域。它没有 "一个人灵光一闪发明" 的戏剧性故事,但它的思路完全贴合普通人的直觉 ------ 比如你想找朋友圈里和你隔 3 个人的好友,就是先找直接好友(1 层)、再找他们的好友(2 层)、最后找这层人的好友(3 层),直到找到目标。

二、BFS 的核心作用:解决 "步数最少" 的问题

BFS 的核心价值就在于 "层层扩散" 的特性,主要能解决两类问题:

  1. 最核心 :在无权图(所有边没有权重 / 权重都相同) 中,找到从起点到目标的最短路径(步数最少) ------ 比如迷宫里 "最少走几步到出口"、朋友圈 "你和 XX 隔了几个人";
  2. 其他常用作用
    • 遍历图 / 树的所有节点(比如爬虫从一个网页出发,爬完整个网站的所有页面);
    • 判断两个节点是否可达(比如判断迷宫里起点能不能到出口、两个用户是否在同一个社交网络里);
    • 找离起点最近的所有目标(比如找你家周边 1 公里内的所有超市)。

三、BFS 的具体可执行代码(朋友圈找人示例)

下面用 "找朋友圈里和你隔几步的好友" 为例,写一个通俗易懂的 BFS 代码,注释详细,可直接复制运行。

python 复制代码
from collections import deque

def bfs_friend_circle(friend_graph, start_person, target_person):
    """
    BFS实现:找朋友圈中从start_person到target_person的最短步数(隔几个人)
    :param friend_graph: 朋友圈关系图,格式为 {人: [好友列表], ...}
    :param start_person: 起点(你)
    :param target_person: 目标(要找的人)
    :return: 最短步数(比如直接好友返回1,无交集返回-1),最短路径(比如["你", "张三", "李四"])
    """
    # 1. 异常处理:起点/目标不在朋友圈里
    if start_person not in friend_graph or target_person not in friend_graph:
        return -1, []
    # 2. 特殊情况:找自己
    if start_person == target_person:
        return 0, [start_person]
    
    # 3. 初始化:队列(存储待探索的人+当前步数+路径),已访问集合(避免重复找)
    # deque是Python的双端队列,popleft()效率高,适合BFS的"先进先出"
    queue = deque()
    queue.append((start_person, 0, [start_person]))  # (当前人, 步数, 路径)
    visited = set()
    visited.add(start_person)
    
    # 4. 核心循环:层层探索好友
    while queue:
        # 取出队列最前面的人(保证"层层处理")
        current_person, current_step, current_path = queue.popleft()
        
        # 遍历当前人的所有好友
        for friend in friend_graph[current_person]:
            # 如果好友是目标,直接返回结果
            if friend == target_person:
                new_path = current_path + [friend]
                return current_step + 1, new_path
            
            # 如果好友没被访问过,加入队列继续探索
            if friend not in visited:
                visited.add(friend)
                new_path = current_path + [friend]
                queue.append((friend, current_step + 1, new_path))
    
    # 5. 遍历完都没找到,说明无交集
    return -1, []

# ------------------- 测试代码 -------------------
if __name__ == "__main__":
    # 构建朋友圈关系图
    # 说明:"你"的好友是"张三""李四";"张三"的好友是"你""王五";"王五"的好友是"张三""赵六";以此类推
    friend_graph = {
        "你": ["张三", "李四"],
        "张三": ["你", "王五"],
        "李四": ["你", "赵六"],
        "王五": ["张三", "赵六"],
        "赵六": ["李四", "王五", "孙七"],
        "孙七": ["赵六"],
        "周八": ["吴九"],
        "吴九": ["周八"]
    }
    
    # 测试1:找"你"到"孙七"的最短步数和路径
    step, path = bfs_friend_circle(friend_graph, "你", "孙七")
    if step == -1:
        print("你和孙七不在同一个朋友圈里")
    else:
        print(f"你到孙七最短需要隔{step}个人,路径:{' -> '.join(path)}")
    
    # 测试2:找"你"到"周八"的最短步数和路径
    step2, path2 = bfs_friend_circle(friend_graph, "你", "周八")
    if step2 == -1:
        print("\n你和周八不在同一个朋友圈里")
    else:
        print(f"你到周八最短需要隔{step2}个人,路径:{' -> '.join(path2)}")
代码运行结果
复制代码
你到孙七最短需要隔3个人,路径:你 -> 张三 -> 王五 -> 赵六 -> 孙七

你和周八不在同一个朋友圈里
代码关键部分解释
  1. 队列(deque):BFS 的核心工具,用 "先进先出" 保证 "层层处理"------ 先处理完 "你" 的直接好友,再处理好友的好友,不会漏掉任何一层;
  2. 已访问集合(visited):避免重复探索(比如 "你" 找 "张三","张三" 又找 "你",会无限循环);
  3. 路径记录:每个队列元素都带 "当前路径",找到目标时直接返回完整路径,不用额外回溯;
  4. 步数计算:每往下一层,步数 + 1,保证返回的是 "最少步数"。

四、总结

  1. 故事核心:BFS 像 "迷宫里层层找出口",核心是 "先进先出、地毯式扩散",没有戏剧性发明故事,但贴合日常思维;
  2. 核心作用:解决无权图的 "最短步数" 问题,还能遍历图、判断节点是否可达(比如朋友圈是否有交集);
  3. 代码关键:用队列(deque)实现 "层层处理",用已访问集合避免循环,是入门图算法的首选。
相关推荐
R1nG8636 小时前
CANN资源泄漏检测工具源码深度解读 实战设备内存泄漏排查
数据库·算法·cann
_OP_CHEN7 小时前
【算法基础篇】(五十六)容斥原理指南:从集合计数到算法实战,解决组合数学的 “重叠难题”!
算法·蓝桥杯·c/c++·组合数学·容斥原理·算法竞赛·acm/icpc
TracyCoder1237 小时前
LeetCode Hot100(27/100)——94. 二叉树的中序遍历
算法·leetcode
九.九7 小时前
CANN HCOMM 底层机制深度解析:集合通信算法实现、RoCE 网络协议栈优化与多级同步原语
网络·网络协议·算法
C++ 老炮儿的技术栈7 小时前
Qt Creator中不写代如何设置 QLabel的颜色
c语言·开发语言·c++·qt·算法
子春一7 小时前
Flutter for OpenHarmony:构建一个 Flutter 数字消消乐游戏,深入解析网格状态管理、合并算法与重力系统
算法·flutter·游戏
草履虫建模13 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq16 小时前
分布式系统安全通信
开发语言·c++·算法
Jasmine_llq16 小时前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
爱吃rabbit的mq17 小时前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习