关于子函数

本周进行了函数的学习,函数除了主函数(即main)外,还有子函数(即由自己定义的函数),这篇文章就来谈谈我对子函数的几点见解。
首先说子函数的使用形式,很多教材上直接是只有定义,调用两部分,即
void 函数名() ——定义
{
… ——调用
}
但事实上子函数的使用形式分为三步:声明,定义,调用,即
void 函数名();——声明
void 函数名() ——定义
{
… ——调用
}
当然声明的一步的确是可以省略,但是C语言程序不只是一些小程序,慢慢我们会接触到更复杂,更庞大的C语言程序,并且有些程序并不是我们自己独立完成的,而是需要一个团队中多人的配合来完成的,到了这些时候声明的意义就出现了。一个几千行的程序,十几或是几十个子函数,如果没有声明这一步,那可能一个人写完的程序另一个人需要花费很长时间才能理解这个程序在干什么,甚至是无法理解,所以声明这一步还是很有必要的。
另外一点我想分享的便是一个程序中多个子函数的输入格式,当然这只是我个人比较喜欢的一种,也自认为表达比较清晰,即
void f1();
void f2();

void fn();
void fn()
{
}

void f2()
{
}
void f1()
{
}
这样调用的子函数就容易查找并且对应其作用,相对于一些教材上一个一个输入较为简单一些。
当然以上只是我的个人见解,到现在我还只是一个小白,懂得还比较少,只是想分享自己的看法,并无它意,如有错误,还望斧正。

<think>嗯,用户问的是“抽取子函数是什么意思”,需要我来解释这个概念。首先,我要回想一下之前的对话历史,用户之前询问过关于LeetCode和牛客网代码降重的方法,而我在回答中提到了抽取子函数作为其中一种方法。现在用户可能想更深入了解这个概念,或者是在实际应用中遇到了相关问题。 首先,我需要确定“抽取子函数”这个术语的定义。抽取子函数,也就是函数抽取,是指将一段代码中的某部分功能独立出来,形成一个单独的函数。这样做的目的是为了代码复用、结构清晰、降低复杂度等。在代码降重的上下文中,用户可能关心的是如何通过这种方法来避免代码重复,从而通过查重系统。 接下来,我需要考虑用户可能的背景。用户可能是在准备编程面试,或者在刷题时遇到了查重的问题。他们可能已经尝试过一些方法,比如变量重命名,但发现效果不佳,因此想了解更有效的方式,如抽取子函数。用户的需求不仅仅是了解定义,更想知道具体的应用场景和实际例子,以及这样做为什么能帮助降重。 然后,我需要分析用户可能存在的深层需求。他们可能对代码结构优化不太熟悉,或者虽然知道抽取子函数的概念,但不确定如何正确应用,尤其是在算法题中如何平衡代码的可读性和效率。此外,用户可能担心抽取子函数是否会影响代码性能,或者是否适用于所有类型的题目。 接下来,我要组织回答的结构。首先给出明确的定义,说明什么是抽取子函数,然后解释其作用,特别是针对降重的意义。接着,通过具体的例子来演示如何操作,比如将一个长函数拆分成多个子函数。同时,需要指出适用的场景和注意事项,帮助用户理解何时使用以及潜在的风险,比如性能影响。 在举例时,要选择用户熟悉的场景,比如LeetCode中的算法题。例如,处理二叉树的题目,原本将所有逻辑放在一个函数里,抽取遍历部分作为子函数。或者排序算法中将分区操作独立出来。这些例子能让用户直观地理解方法的应用。 还要考虑用户可能存在的误区,比如认为只要抽取子函数就能完全避免查重,但实际上查重系统可能通过AST分析代码结构,所以需要更深入的逻辑重构。因此,在回答中需要强调,抽取子函数需要结合其他方法,如改变逻辑结构或算法替换,才能有效降重。 最后,总结抽取子函数的优缺点,提醒用户在实际应用中权衡代码的可读性、维护性和性能,确保在降重的同时不牺牲代码质量。同时,鼓励用户通过练习掌握这一技巧,从根本上提升编码能力,这才是应对查重的根本方法。</think>### **抽取子函数** 的完整解析 **定义**: 将代码中 **重复出现** 或 **功能独立** 的代码段分离出来,封装成独立的函数(子函数)。这是代码重构(Code Refactoring)的核心手段之一,在算法题降重中常用于 **改变代码结构层级**。 --- ### **一、核心作用** | 应用场景 | 降重原理 | 典型示例 | |--------------------|----------------------------|--------------------------| | **消除重复代码** | 将重复逻辑统一到单一函数,避免相同代码多次出现 | 合并多个位置的排序操作 | | **隐藏核心逻辑** | 将关键算法步骤封装为函数,破坏原始代码的连续性 | 将快速排序的 `partition` 独立 | | **改变抽象层级** | 通过函数调用替代直接实现,修改语法结构 | 用 `calculate_sum()` 代替累加代码 | --- ### **二、实际操作示例** #### **场景**:检测回文链表 **原始代码(未抽取子函数)**: ```python def isPalindrome(head): # 找中点 slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next # 反转后半部分 prev = None while slow: tmp = slow.next slow.next = prev prev = slow slow = tmp # 比较前后半段 left, right = head, prev while right: if left.val != right.val: return False left = left.next right = right.next return True ``` **降重修改(抽取子函数)**: ```python def _find_mid(node): # 抽取找中点逻辑 slow = fast = node while fast and fast.next: slow = slow.next fast = fast.next.next return slow def _reverse_list(node): # 抽取反转链表逻辑 prev = None while node: next_node = node.next node.next = prev prev = node node = next_node return prev def isPalindrome(head): mid = _find_mid(head) reversed_half = _reverse_list(mid) p1, p2 = head, reversed_half while p2: if p1.val != p2.val: return False p1 = p1.next p2 = p2.next return True ``` --- ### **三、降重有效性分析** 1. **语法结构变化**: - 原代码的 `while` 循环被封装为函数调用 - 控制流从 **线性连续执行** 变为 **分层调用结构** 2. **AST(抽象语法树)差异**: - 原始代码:包含3个并列的 `while` 节点 - 重构后:出现 `FunctionDef` 节点与 `Call` 节点 3. **查重系统视角**: - 子函数内部的实现细节与主函数的调用关系构成新的结构模式 - 比直接修改变量名/注释的降重效果更显著 --- ### **四、适用场景与注意事项** #### **最佳使用场景** - 代码中存在 **明显可复用的功能模块**(如链表操作、树遍历) - 问题需要 **多步骤处理**(如动态规划问题拆分为状态初始化+转移计算) - 算法包含 **标准子过程**(如排序、二分查找) #### **注意事项** 1. **避免过度拆分**: - 每个子函数应有明确单一职责 - 函数过多可能导致可读性下降 2. **性能考量**: - 函数调用会增加栈开销(对时间要求极严的题目慎用) - Python等解释型语言需注意函数调用成本 3. **命名规范**: - 使用 `_` 前缀表示内部函数(如 `_helper()`) - 函数名需准确描述功能(如 `_merge_two_sorted_lists`) --- ### **五、高级技巧** 1. **多级封装**: 对子函数进一步拆分,形成 `函数A → 函数B → 函数C` 的调用链 ```python def main(): data = _load_data() processed = _preprocess(data) return _calculate(processed) def _load_data(): ... def _preprocess(raw): ... def _calculate(input): ... ``` 2. **闭包封装**: 通过闭包隐藏局部变量,增强代码隔离性 ```python def create_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter ``` 3. **类方法封装**: 在面向对象解法中将子功能封装为类方法 ```python class Solution: def isPalindrome(self, head): mid = self._find_mid(head) # ... def _find_mid(self, node): ... def _reverse_list(self, node): ... ``` --- ### **六、与其他降重方法的结合** - **+ 逻辑重构**:在子函数内部使用不同的实现方式(如将递归改为迭代) - **+ 数据结构替换**:子函数的输入/输出改用不同数据结构 - **+ 语言特性**:在子函数中使用生成器、装饰器等特性 > **重要提示**:单纯抽取子函数可能无法完全绕过AST级别的查重,需配合 **逻辑变形**(如改变循环顺序)或 **算法替换** 才能显著降低重复率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值