news 2026/1/13 21:46:11

【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/1/13 2:17:59

yaml-cpp内存优化策略深度解析:从性能瓶颈到高效解决方案

yaml-cpp内存优化策略深度解析&#xff1a;从性能瓶颈到高效解决方案 【免费下载链接】yaml-cpp A YAML parser and emitter in C 项目地址: https://gitcode.com/gh_mirrors/ya/yaml-cpp 在C项目开发中&#xff0c;YAML配置文件的解析性能往往成为系统瓶颈&#xff0c;…

作者头像 李华
网站建设 2026/1/9 22:13:51

JSP如何结合多线程技术提升大文件上传效率?

大文件传输解决方案技术提案 项目背景与需求分析 作为山东某软件公司项目负责人&#xff0c;我公司需要为大文件传输提供一套完整的解决方案。经过详细的需求梳理&#xff0c;总结出以下几个关键需求点&#xff1a; 大文件传输能力&#xff1a;支持单文件100GB左右的上传下载…

作者头像 李华
网站建设 2026/1/10 1:00:25

ChanlunX缠论插件:让技术分析变得简单直观的智能助手

你是否曾在K线图中迷失方向&#xff1f;面对密密麻麻的K线图&#xff0c;是否感到无从下手&#xff1f;&#x1f914; 今天&#xff0c;让我们一起来了解ChanlunX缠论插件如何通过智能化算法&#xff0c;将复杂的技术分析变得简单直观。 【免费下载链接】ChanlunX 缠中说禅炒股…

作者头像 李华
网站建设 2026/1/9 2:11:55

光伏储能系统搭上虚拟同步发电机(VSG)这趟车,简直像是给新能源装了个智能大脑。今儿咱们直接上硬菜,拆解这个能跑出完美波形的并网仿真模型

光伏储能虚拟同步发电机VSG并网仿真模型C 光伏阵列搭建的光伏电池模型 光伏&#xff1a;采用扰动观察法最大功率点MPPT跟踪控制 储能&#xff1a;蓄电池充放电控制&#xff0c;双向Buck/Boost变换器&#xff0c;采用直流母线电压外环控制稳定直流母线电压&#xff0c;电池电流内…

作者头像 李华
网站建设 2026/1/13 11:01:44

在一台电脑上生成多个ssh公钥并添加到不同GitHub账号

在同一台电脑上操作多个 GitHub 账号的仓库 为每个账号生成独立的 SSH 密钥对&#xff0c;然后通过配置来区分使用。 步骤&#xff1a;为每个账号生成独立的 SSH 密钥&#xff1a; ssh-keygen -t ed25519 -C "your-email1example.com" -f ~/.ssh/id_ed25519_personal…

作者头像 李华