关于递归思考msort函数的若干技术疑问
以Graham Hutton讲解的归并排序函数msort为例,教授在还没写完msort的完整定义时,就直接说msort ys和msort zs是已排序列表,之后才补充merge函数完善整个定义。针对这个场景,三个核心疑问的解答如下:
1. 为何msort未完全定义时就能谈论msort ys?
这是递归思维里归纳假设的核心逻辑:在设计递归函数时,我们会先假定——对于规模更小的输入(这里ys是原列表拆分后的子列表,长度肯定比原列表短),递归调用已经能正确完成任务(也就是返回已排序列表)。
这个假设不是凭空而来:递归的终止条件(比如空列表、单元素列表本身就是有序的)能保证最基础的情况绝对成立,再通过归纳步骤(用merge把两个有序子列表合并),就能把小问题的解组合成大问题的解。所以哪怕还没写完整个函数,我们也能基于这个假设有条理地推导后续逻辑。
2. 称msort ys为已排序列表这类表述仅用于辅助函数推理吗?
不止是辅助推理,这其实是递归函数正确性证明的核心环节。
当我们说msort ys是已排序列表时,本质是在明确递归调用的预期行为——这既是我们推导merge函数需求的直接依据(merge必须能接收两个有序列表,再返回一个有序列表),也是后续证明整个msort函数正确性的关键前提。
另外在教学场景里,这种表述能帮学习者快速抓住递归的核心:不用纠结底层细节,先聚焦“子问题已经解决,怎么把这些解拼起来”这个核心逻辑。
3. 是否默认halve会被合理定义?
是的,在递归设计的语境下,我们会把halve这类辅助函数当成“功能明确的黑盒”——它的职责就是把原列表拆分成两个长度相近的子列表,只要能稳定完成这个任务就行。
在归并排序的核心逻辑里,halve的具体实现(比如按长度拆分、按奇偶位置拆分)不会影响msort的整体正确性,所以在设计msort的递归结构时,我们只需要依赖halve的功能,不用先去实现它。当然,最终要让msort跑起来,halve必须被正确实现,但这属于后续细节层面的工作。
内容的提问来源于stack exchange,提问作者F. Zer

