news 2026/9/26 8:50:04

【30天从零学Python】重要补充四、检测有向环 - Kahn算法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【30天从零学Python】重要补充四、检测有向环 - Kahn算法

30天从零学Python

通信工程专业科班生,用了几十年MATLAB,为了过大厂机考,不得不自学Python。

文章目录

  • 30天从零学Python
  • 重要补充四、检测有向环 - Kahn算法
  • 1. 有向环与拓扑排序
    • 1.1 Kahn 算法核心原理(通俗版)
    • 1.2 Kahn 算法代码实现(适配函数调用场景)
  • 2. 主要坑点
    • 2.1 Kahn 算法坑点
  • 总结

重要补充四、检测有向环 - Kahn算法

本集重点补充用于检测有向环的 Kahn 算法(拓扑排序的经典实现),该算法能高效检测函数调用、任务依赖等场景中是否出现循环依赖(比如 A 调用 B、B 调用 C、C 又调用 A),是大厂机考中高频考点。


1. 有向环与拓扑排序

  • 在函数调用场景中,有向环就是循环调用(比如函数 A 调用 B,B 又调用 A),这种情况会导致栈无限增长。
  • 拓扑排序是对有向无环图(DAG)的节点进行排序,使得所有有向边从排序靠前的节点指向靠后的节点。Kahn 算法通过拓扑排序的过程,能直观检测出图中是否存在环。

1.1 Kahn 算法核心原理(通俗版)

Kahn 算法像 “剥洋葱” 一样处理节点:

  1. 先统计每个节点的入度(有多少个节点指向它,对应 “有多少个函数调用当前函数”);
  2. 把所有 “入度为 0” 的节点(无被调用的起始函数)加入队列;
  3. 不断从队列取出节点,删除该节点的所有出边(即把它指向的节点入度减 1);如果某个节点入度减到 0,就加入队列;
  4. 最终如果处理的节点数 <总节点数,说明存在环(剩下的节点形成闭环,无法被 “剥完”)
    图片说明:
    假设有5个函数,用节点1,2,3,4,5表示,箭头a指向b表示a调用b。
    在这里插入图片描述

1.2 Kahn 算法代码实现(适配函数调用场景)

fromcollectionsimportdequedefhas_cycle(func_calls):""" 检测函数调用关系中是否存在有向环 :param func_calls: 函数调用关系,格式为 {(调用者): [(被调用者, 内存)], ...} :return: (是否有环, 拓扑排序结果) """# 1. 统计所有函数节点all_funcs=set()forcallerinfunc_calls:all_funcs.add(caller)forcallee,_infunc_calls[caller]:all_funcs.add(callee)all_funcs=list(all_funcs)# 2. 初始化入度字典(key:函数,value:入度)in_degree={func:0forfuncinall_funcs}forcallerinfunc_calls:forcallee,_infunc_calls[caller]:in_degree[callee]+=1# 被调用者入度+1# 3. 初始化队列:入度为0的节点(起始函数)queue=deque()forfuncinall_funcs:ifin_degree[func]==0:queue.append(func)# 4. 执行Kahn算法processed=0# 记录处理过的节点数topo_order=[]# 拓扑排序结果whilequeue:current=queue.popleft()topo_order.append(current)processed+=1# 遍历当前节点的所有被调用者,入度减1ifcurrentinfunc_calls:forcallee,_infunc_calls[current]:in_degree[callee]-=1ifin_degree[callee]==0:queue.append(callee)# 5. 判断是否有环:处理节点数 < 总节点数 → 有环has_cycle_flag=processed<len(all_funcs)returnhas_cycle_flag,topo_order# 测试案例1:无环(正常函数调用)if__name__=="__main__":# 案例1:0→1(128),1→2(128)(无环)call_map1={0:[(1,128)],1:[(2,128)]}cycle1,topo1=has_cycle(call_map1)print(f"案例1 - 是否有环:{cycle1},拓扑排序:{topo1}")# 输出:False,[0,1,2]# 案例2:0→1,1→2,2→0(有环)call_map2={0:[(1,100)],1:[(2,200)],2:[(0,300)]}cycle2,topo2=has_cycle(call_map2)print(f"案例2 - 是否有环:{cycle2},拓扑排序:{topo2}")# 输出:True,[](无入度为0的节点)

2. 主要坑点

2.1 Kahn 算法坑点

  1. 统计节点时容易遗漏:必须包含 “调用者” 和 “被调用者” 所有函数,否则会误判环;
  2. 入度初始化要覆盖所有节点:即使是入度为 0 的起始函数,也要初始化入度为 0;
  3. 队列处理时要遍历当前节点的所有出边:避免漏减被调用者的入度。

总结

总结

  1. Kahn 算法是检测有向环的高效方法,核心是 “入度统计 + 队列处理”,适配函数调用循环依赖检测;
  2. 实现 Kahn算法时要确保覆盖所有节点、正确维护入度。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 5:21:22

2025年B站视频下载终极指南:bilili工具完整使用教程

2025年B站视频下载终极指南&#xff1a;bilili工具完整使用教程 【免费下载链接】bilili :beers: bilibili video (including bangumi) and danmaku downloader | B站视频&#xff08;含番剧&#xff09;、弹幕下载器 项目地址: https://gitcode.com/gh_mirrors/bil/bilili …

作者头像 李华
网站建设 2026/9/25 14:53:13

教程 32 - 几何体系统

上一篇&#xff1a;材质系统 | 下一篇&#xff1a;资源系统 | 返回目录 &#x1f4da; 快速导航 &#x1f4cb; 目录 引言学习目标几何体概念几何体数据结构几何体系统架构几何体配置与创建程序化几何体生成渲染器集成渲染包系统使用示例常见问题练习与挑战下一步 &#x1f4d…

作者头像 李华
网站建设 2026/9/26 8:34:59

Cursor高级技巧与最佳实践

Cursor 高级技巧与最佳实践&#xff08;2025 年 12 月最新版&#xff09; 掌握 Cursor 的高级用法&#xff0c;能让你从“用 AI 写代码”进化到“与 AI 协作如高级搭档”。以下技巧基于 2025 年社区最佳实践&#xff08;如 Builder.io、DEV Community、Cursor 官方文档&#x…

作者头像 李华
网站建设 2026/9/25 14:53:19

Cursor + MCP:冲击的不仅是前端,而是整个软件开发范式!

Cursor MCP&#xff1a;冲击的不仅是前端&#xff0c;而是整个软件开发范式&#xff01; 是的&#xff0c;你说得太对了&#xff01;Cursor Model Context Protocol (MCP) 的组合&#xff0c;正在从前端出发&#xff0c;迅速向全栈、后端、自动化测试、部署甚至非编程领域&a…

作者头像 李华
网站建设 2026/9/25 5:45:30

2025年十大旗舰对决:极致轻薄成高端手机新战场

移动通信技术持续演进着&#xff0c;消费者对于智能手机的期待&#xff0c;不再仅仅局限于性能的强劲&#xff0c;机身设计方面极致的纤薄以及轻盈&#xff0c;现已成为高端市场的一项重要追求&#xff0c;到了2025年&#xff0c;这一趋势抵达了新的高度&#xff0c;好多款旗舰…

作者头像 李华
网站建设 2026/9/25 14:52:52

【Vue3】 中 ref 与 reactive:状态与模型的深入理解

目录Vue3 中 ref 与 reactive&#xff1a;状态与模型的深入理解一、概念区分&#xff1a;状态 vs 模型状态&#xff08;State&#xff09;模型&#xff08;Model / 业务模型&#xff09;二、ref vs reactive 使用原则三、典型使用示例状态&#xff08;ref&#xff09;模型&…

作者头像 李华