2026-05-24 ·
日常编程 ·
81837
为什么不用list而要用deque实现BFS队列
因为list.pop(0)是O(n)操作,每次从头部弹出都会移动后面所有元素;而deque.popleft()是O(1),BFS频繁出入队时性能差距会指数级放大。实测10万节点图上,list版本可能卡顿数秒,deque几乎瞬时完成。
常见错误是写成queue = []; queue.pop(0),尤其新手从循环队列概念直接套用列表索引,结果在稍大规模数据下超时或被判定为算法低效。
必须从collections导入:from collections import deque
初始化写法是queue = deque([start_node]),不是deque(start_node)(后者会把节点拆成字符/元素)
入队统一用append(),出队统一用popleft()——别混用pop(),否则变成DFS行为
deque版BFS的标准骨架怎么写
核心就三步:初始化队列、循环取点、对未访问邻居入队。关键在于访问标记必须在入队时做,而不是出队时做,否则同一节点可能被重复加入多次。
from collections import deque
def bfs(graph, start):
visited = set([start])
queue = deque([start])
while queue:
node = queue.popleft()
print(node) # 处理当前节点
for neighbor in graph.get(node, []):
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor) # 入队即标记,防重入
注意:graph通常为dict,键是节点,值是邻接节点列表;若用邻接矩阵,遍历逻辑要改为索引扫描,但deque用法不变。
遇到层级遍历(如二叉树层序)怎么改
BFS天然适合分层,关键是每次循环前记录当前队列长度,作为本层节点数。这不是额外开数组,而是利用len(queue)的O(1)特性。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
不要在循环中动态查len(queue),必须在每轮开头固定一次:for _ in range(len(queue)):
如果需要返回每层结果,用level_nodes = []收集本轮node,再result.append(level_nodes)
图结构做层级遍历时,仍需严格维持“入队即标记”,否则跨层重复访问会污染层级边界
示例片段:
while queue:
level_size = len(queue)
current_level = []
for _ in range(level_size):
node = queue.popleft()
current_level.append(node)
for n in graph[node]:
if n not in visited:
visited.add(n)
queue.append(n)
实际调试时deque容易被忽略的细节
最常踩的坑是误以为deque支持下标随机访问——它确实支持q[0]或q[-1],但这是O(n)操作(内部是双向链表),千万别在BFS主循环里写queue[0]代替popleft(),否则整个算法退化成O(n²)。
检查是否意外调用了queue.pop()(右侧出队)导致顺序错乱
多线程场景下deque不安全,但纯BFS单线程无需加锁
内存上,deque比list略高一点,但换来的性能提升远超这点开销,不必纠结
如果用deque(maxlen=N)做了限制,BFS中途可能丢节点——除非你明确要做滑动窗口式搜索,否则别设maxlen
真正难的从来不是写出BFS,而是当图变大、逻辑嵌套加深、还要兼容多种输入格式时,依然守住“入队即标记”和“只用popleft/append”这两条底线。
因为__new__不是原子操作:线程A判断_instance为None后,未执行super().__new__前,线程B也判为None,导致重复创建;GIL不保护跨语句逻辑,需用双重检查锁定(DCL)加threading.Lock确保线程安全。 为什么直接用 __new__ 实现单例在多线程下会失效 因为 __new__ 本身不是原子操作:线程 A 判断 _instance 为 None 后,还没...
2026-05-29 · 日常编程 · 34337
递归DFS栈溢出风险高因CPython默认递归深度仅1000,长链或环易触发RecursionError;隐式栈不可控,闭包和帧对象加剧内存开销;图应优先用显式栈实现。 递归实现DFS时,为什么栈溢出风险比预期高? Python默认递归深度限制是1000层,图中存在长链或环状结构时极易触发RecursionError。这不是算法错,而是CPython解释器对递归调用的硬性约束。 用sys.setr...
2026-05-29 · 日常编程 · 104233
RabbitMQ本身保证单条消息只投递一次给一个消费者,数据一致性问题源于业务逻辑并发执行导致的竞态,而非消息重复投递;basic_ack仅确认消息接收,不保障业务执行唯一性,故无法解决数据一致性问题。 多进程消费同一个RabbitMQ队列时,数据一致性问题不来自RabbitMQ本身(它天然保证单条消息只投递一次给一个消费者),而来自业务逻辑并发执行导致的竞态——比如多个进程同时读写同一张数据库表...
2026-05-29 · 日常编程 · 286614
RabbitMQ延迟队列需通过TTL+死信交换机(DLX)组合实现,精度秒级、延迟时间publish时固定为字符串毫秒值,且必须完整配置x-dead-letter-exchange与x-dead-letter-routing-key,否则消息丢弃。 延迟队列不是RabbitMQ原生功能,得靠TTL+死信交换机组合实现 rabbitmq本身没有x-delayed-message插件以外的内置延迟队列...
2026-05-29 · 日常编程 · 224807
Pandas 的 MultiIndex 不是手写嵌套字典或类实现的,而是通过 pd.MultiIndex.from_tuples()、from_product() 或 set_index() 构建的索引层;手动模拟会丧失对齐、切片、重采样等核心能力。 直接说结论:Pandas 的 MultiIndex 不是“自己实现”的数据结构,而是用现成的 pd.MultiIndex.from_tuples()...
2026-05-28 · 日常编程 · 241228
本文介绍如何使用 pandas 的 pivot_table 和 categorical 配合 fill_value 参数,将原始流动数据(含 origin-destination 地理编码和流量值)高效转换为指定地理单元集合的 n×n 流量矩阵,缺失组合自动补零。 本文介绍如何使用 pandas 的 pivot_table 和 categorical 配合 fill_value 参数,将原始流动数...
2026-05-28 · 日常编程 · 268559
RabbitMQ的vhost不宜直接作租户隔离单位,因其不支持运行时动态增删、管理成本高、连接数易指数级上涨;应改用消息头tenant_id或routing key前缀实现逻辑隔离,并结合DLX+TTL实现可控重试。 为什么 RabbitMQ 的 vhost 不能直接当租户隔离单位用 因为 vhost 是权限和资源隔离边界,但不支持运行时动态创建/销毁,且管理成本高——每次新增租户都要调用 PUT...
2026-05-28 · 日常编程 · 258105
一致性哈希通过固定哈希空间(如2^32)构建环形结构,节点和数据映射其上并顺时针就近分配;增删节点仅影响邻近区间,大幅减少数据迁移;引入虚拟节点可缓解物理节点分布不均问题,提升负载均衡性。 直接用 hash_ring 库最省事,但真要自己写、调参或排查分布不均问题,必须理解虚拟节点数量、哈希函数输出范围、环结构更新时机这三个关键点。 为什么简单取模(hash(key) % N)在节点变动时会崩 节...
2026-05-28 · 日常编程 · 47980
直接obj.likes += 1在并发下丢数据,是因为该操作分“读-改-写”三步:先查出旧值(如99),Python内存中加1得100,再保存;若两个请求同时执行,均基于99计算并写入100,最终结果为100而非102,造成更新丢失。 为什么直接 obj.likes += 1 在并发下会丢数据 多个用户几乎同时点赞时,Django 默认先查出当前 likes 值(比如 99),各自加 1 得到 1...
2026-05-28 · 日常编程 · 156527
LabelPropagation要求数据具备局部平滑性,特征须标准化,未标记样本标签必须为-1,且需至少两个已标记类别;拟合用transduction_获取全部预测,不提供置信度,对噪声敏感。 LabelPropagation 在 scikit-learn 中的适用前提 LabelPropagation 不是万能半监督工具,它要求数据天然具备“局部平滑性”——即相似样本大概率共享标签。如果特征空间...
2026-05-28 · 日常编程 · 252780