上一章里,普通归纳的节奏很整齐:先站稳起点,再把 推到 。可离散数学里的对象不总排成一条只看前一步的队伍。一棵树会分成左右两棵子树,一个合数会拆成两个更小因子,斐波那契数的下一项要同时回看前两项。此时如果归纳假设只给我们 ,手里的材料就不够顺手了。
这一章要做的,是把“向更小对象追溯”这件事讲清楚。强归纳允许我们调用全部更小情形;良序原理把“若真有失败者,就取最小的那个”变成严密论证;递归定义则从相反方向出发,说明复杂对象怎样由简单对象一步步造出来。三条线最后会在结构归纳和递归过程里汇合。
本章约定 。若命题从 、 或其他整数开始,只要把基础情形和归纳假设的下界一同平移,证明结构不会改变。
先把一句容易误解的话说准:强归纳在逻辑能力上并不比普通归纳更强。凡是强归纳能证明的自然数命题,都能改写成普通归纳证明。我们说“普通归纳不够用”,通常是指只假设紧邻前件 的那种直接写法,拿不到当前证明真正需要的较小情形。
例如,要证明整数 能写成素数的乘积,最自然的第一步不是研究 ,而是把 拆成 。随后我们需要的是“ 可以分解”和“ 可以分解”。这两个下标都比 小,却都不是 。如果归纳假设只交给我们 ,它与眼前的分解结构根本接不上。

强归纳正是把假设范围放宽。要证明对所有 ,命题 成立,可以使用下面的形式:
并且对每个 ,证明
于是得到
这里最要紧的边界是 。归纳步骤允许假设的是所有严格更小的情形,不包括正在证明的 。因此它没有把结论偷偷塞进前提,也不是循环论证。
先把命题写成清楚的 ,同时标明起点 。如果不先固定论域,后面很容易调用到归纳假设没有覆盖的下标。
证明必要的基础情形。基础情形可能只有一个,也可能是一段连续的数;数量由归纳步骤向前回看的距离决定。

下面的交互图可以在普通归纳和强归纳之间切换。拖动目标 时,留意两种模式究竟开放了哪些可调用前提。
“假设所有更小情形成立”不能替代基础情形。若证明从 开始,却没有直接证明 ,那么整条推理没有落脚点。强归纳给了更多可用前提,并没有免除起点检查。
我们来证明:每个整数 都能写成一个或多个素数的乘积。这里证明的是分解存在,不讨论分解是否唯一。
动笔前先暴露一下思路。目标是“素数乘积”,所以先问 本身是不是素数。如果不是,合数的定义会把它拆成两个真因子。真因子严格小于原数,这就给强归纳假设留出了入口。

令 表示“整数 可以写成一个或多个素数的乘积”。
基础情形取 。因为 本身是素数,所以把它看成只有一个因子的乘积, 成立。
取任意 ,假设所有满足 的整数都可以写成素数乘积。现在要证明 。
为什么普通归纳的直接写法别扭,现在看得很清楚了。合数 的两个因子可能离 很远;证明需要 和 ,强归纳假设恰好同时提供它们。
不要在“ 是合数”后直接写“由归纳假设,两个因子都能分解”。必须先说明 。若较小对象没有落进归纳假设的范围,这次调用就是无效的。
强归纳题里常见连续多个基础情形。它们不是为了让证明显得完整,而是在填补归纳步骤无法覆盖的起始空档。
考虑命题:每个不小于 的整数,都可以写成若干个 与若干个 的和。令
我们的构造动作是“先组成 ,再加一个 ”。这条动作只有在 时才能调用归纳假设,也就是从 才开始运转。因此 必须先逐个封住。

验证四个基础情形:,,,。
这个例子给出一个实用检查法:如果归纳步骤要回看前 个位置,通常要检查最前面的 个连续情形。这里每次减 ,所以先处理四个连续起点。只验证 的话,、、 仍然无从得到。
良序原理说得很短:自然数的每个非空子集都有最小元素。用符号写就是,只要 且 ,就存在 ,使得

定义里有两个条件都不能少。空集没有元素,自然谈不上最小元素;对象还必须来自自然数或其他良序集合。正有理数集合虽然非空,却没有最小正数,因为给出任何 ,总能再找到更小的正数 。
还要分清“最小元素”和“下确界”。最小元素必须属于集合本身。良序原理保证的是集合里真有一个最靠前的成员,不只是存在某个集合外的下界。
自然数并不是唯一能这样使用的集合。任何有整数下界的整数集合也都有最小元素:把所有元素减去一个整数下界,就能把问题平移到自然数中。这也解释了为什么证明可以从任意整数起点 开始,不必永远从 开始。
假设我们想证明每个 都满足 。若结论不成立,就把所有失败的下标收集起来:
如果真有反例, 就是非空自然数集合,因此有最小元素 。接下来的任务并不是机械地重复定义,而是利用题目结构让这个最小反例崩掉。常见的崩法有两种:直接证明 其实成立,或者构造出另一个 且 。

假设结论并非处处成立,并定义反例集合 。要明确写出 的论域,不能只说“设 为反例集合”。
由“存在反例”得知 ,再由良序原理取 。
下面的交互页把这条推理放进质因数、邮资和算法终止三个场景。切换场景时,重点看每次选用的“规模”是什么,以及更小对象怎样被迫成为反例。
同一个质因数分解命题可以完全不用“归纳步骤”的格式。
假设有整数 不能写成素数乘积,把它们组成集合 。由良序原理, 有最小元素 。 不会是素数,否则它自己就是一个素数乘积,所以 ,其中 。由于 是最小反例,、 都不在 ,它们都能写成素数乘积。把这两个乘积相乘便得到 的素数分解,与 矛盾。因此 为空。
你会发现,这段证明与前面的强归纳证明几乎共享同一个核心:把合数拆成更小因子。差别只在叙述方向。强归纳说“所有更小情形已成立,所以当前情形成立”;最小反例法说“若当前是最小失败者,更小情形都成功,于是当前也成功,矛盾”。
这三种方法在自然数上证明能力相同,但它们给读者看的思考路径不同。
普通归纳强调相邻传递。若基础情形成立,且每个 都能推出 ,就不存在第一个失败位置:第一个失败位置的前一项本应成功,并把成功传给它。
强归纳强调全部前史。为了证明 ,可以使用所有 ,其中 。如果想把它机械地改成普通归纳,只需定义一个更大的命题
普通归纳证明 时,假设 就等于一次拿到了从 到 的全部信息。这说明强归纳的“更强假设”可以被包装进一个普通归纳命题里。
良序原理强调第一个失败者。若基础情形与推进规则都成立,却仍有反例,那么反例集合有最小元素 。最小性保证所有更小情形成功,推进规则又会迫使 成功,于是矛盾。
选方法时不必追求“更高级”。先问当前对象怎样缩小:只减一,普通归纳往往最清楚;会跳回多个位置或拆成多块,强归纳更自然;如果论证本来就在说“不可能有最小失败者”,良序原理通常最短。
递归定义的表面特征,是定义里再次出现了被定义的对象。可只出现“自己”还不够。一个完整的递归定义必须告诉我们从哪里开始,以及怎样从已经得到的简单对象生成新对象。
对递归定义的集合或数据类型,最好把三件事说全:
第三条有时被写成“这是满足前两条的最小集合”。它防止定义只说明“哪些对象肯定在里面”,却没有排除无关对象。
设数列由下面两条规则定义:
第一条给出起点,第二条把已经定义的 送到下一项。于是

下面的展开器同时展示数列、字符串和二叉树。数列沿下标生长,字符串通过追加字符生长,二叉树则把一个问题分到左右子树。它们外形不同,却都遵守“基础对象加构造规则”的同一套语法。
自然数可以看成一个递归定义的数据类型:
现在回头看普通归纳,它其实就是沿着这份构造说明做结构归纳:先证明基础对象 有性质,再证明构造器“取后继”会保持性质。
对象怎样构造,作用在它上面的递归函数通常就怎样分情况。先规定函数在基础对象上的值,再用较小组成部分的函数值,定义新对象上的函数值。
阶乘沿自然数的后继结构定义:
斐波那契数每次要回看两个位置,所以需要两个基础值:
这里的两个基础值不是惯例装饰。若只给 ,计算 时仍然缺少 ;递归规则不能唯一确定整条序列。
再看字符串。给定字母表 ,用 表示所有有限字符串:
字符串长度可以沿同样的结构递归定义:
注意右边调用的是更短字符串 的长度。递归之所以能启动并得到唯一结果,是因为每次都沿构造历史向基础对象靠近。
下面几类问题要格外小心。
写递归定义时可以做一次“手算审计”:从你想计算的对象出发,连续展开三四步。若下标或结构没有严格变小、不同分支发生重叠,或者始终到不了某个已给值,定义很可能还不完整。
递归定义告诉我们对象怎样造出来,结构归纳则照着同一张施工图证明性质。若递归类型 有若干基础对象和若干构造器,要证明每个 都满足 ,需要完成两类工作:
一个二元构造器 对应的归纳步骤就是
这里为什么会同时出现两个归纳假设?因为新对象是由两个较小对象造出来的。结构归纳假设的数量,跟着构造器的递归参数数量走。
先递归定义连接。固定任意字符串 ,按第一个字符串的结构规定:
我们要证明,对任意 ,都有
证明入口应该选哪个对象?连接的递归定义是沿第一个参数 展开的,所以对 做结构归纳最自然。归纳命题要把另一个参数一并带上:
基础情形取 。对任意 ,由连接和长度的基础规则,,所以 成立。
这份证明没有按字符串长度 明写下标,但每次都从 回到更短的 。如果愿意,也能改成对长度做强归纳;结构归纳的优势是证明版式直接贴着对象的定义,不必另外发明一个数值下标。
设满二叉树递归定义如下:单个叶子是满二叉树;若 、 是满二叉树,则用一个新根连接 和 得到的新树也是满二叉树。
令 表示叶子数, 表示内部节点数。可以用结构归纳证明
基础情形是一片叶子,此时 、。构造情形假设 且 。新树满足
以及
因此
这里若只对左子树使用归纳假设,证明就会断掉。结构归纳必须覆盖构造器中的每个递归组成部分。
递归定义在数学上说明一个对象或函数怎样确定;递归程序还多了一个运行问题:照规则计算时,会不会真的到达基础情形?
常用办法是给每个状态 指定一个自然数度量 ,并证明每次非基础递归调用 都满足

为什么“自然数值且严格下降”足以保证终止?假设存在无限调用链
那么度量值组成严格下降链
把这些度量值组成集合 。由良序原理, 有最小元素 ;可下一次调用又给出更小的 ,矛盾。因此这样的无限调用链不存在。
对整数 ,欧几里得算法使用
把第二个分量 当作度量。除法余数满足
所以每次非基础调用都严格减小第二个分量。它最终只能到达第二个分量为 的基础情形,算法因此终止。
终止证明要同时写出两句话:度量始终落在某个良序集合中;每次真正递归时度量严格变小。只说“问题越来越简单”太含糊,只说“度量不会为负”也不够,因为不严格下降的序列可以永远停在同一个值。
错误写法是“假设 对所有 成立,证明 ”。这个假设已经包含目标。正确边界应是 ;或者把目标写成 ,假设范围写成 。
若递推或构造每次要用 ,通常要先处理两个连续起点。若每次回看 ,就要检查四个余数类别对应的起点。强归纳不会自动填上开头的空档。
“取最小反例”需要先说明反例集合非空,并确认规模来自自然数或另一个良序集合。对正实数、正有理数直接取最小元素通常没有依据。
没有基础对象,生成过程无处开始;没有封闭说明,集合里可能混入没有被规则生成的对象;函数规则若不向更小组成部分靠近,还可能无法唯一确定值。
递归定义若有两个基础对象、三个构造器,证明就必须逐项覆盖。只证明“最常见”的构造方式,不能推出所有递归生成对象都满足性质。
判断下面各题更适合普通归纳、强归纳、最小反例法还是结构归纳,并说明选择依据。
证明每个整数 都可以写成若干个 与若干个 的和。
有人想定义函数 :
这份定义为什么不能直接当作递归计算规则?
满二叉树由“单个叶子”和“把两棵满二叉树接到一个新根下”递归生成。证明每棵满二叉树的节点总数都是奇数。
现在可以把本章的三条线收拢起来了。普通归纳沿自然数的后继一步步走;强归纳在证明当前情形时允许查看全部更小情形;良序原理保证一旦真有失败者,就能抓住最小的那个。递归定义则把对象的生成历史写出来,结构归纳沿这段生成历史反向证明性质。
下一章会把注意力集中到数列。像
或
这样的式子叫递推关系。到那里,我们不只要确认递归定义完整,还会研究怎样展开递推式、猜出封闭公式,再用这一章学过的归纳方法验证猜想。换句话说,本章解决“规则能不能从简单对象生成全部对象”,下一章继续解决“生成出来的数列究竟长什么样”。
取任意 ,假设每个满足 的 都成立。这一整句才是强归纳假设。
把规模为 的对象化成一个或几个规模更小的对象,并逐个检查它们的下标确实落在 内,然后调用相应的 。
用这些较小情形完成 ,最后明确写出“由强归纳法,结论对所有 成立”。
若 是素数, 本身就是长度为一的素数乘积,结论立即成立。
若 是合数,则存在整数 ,使得 且 。这两个严格不等式不能省略,因为它们正是调用归纳假设的许可证。
由强归纳假设, 与 各自都能写成素数乘积。把两串素数因子相乘,就得到 的素数乘积表示。因此无论 是素数还是合数, 都成立。
取任意 ,假设所有满足 的 都成立。
因为 ,所以 在归纳假设的覆盖范围内。于是存在非负整数 ,使得 。
两边加 ,得到 ,所以 成立。由强归纳法,所有 都能这样表示。
使用 的最小性:所有论域中比 小的对象都不是反例,因此它们满足原命题。
分析 的结构,把它缩成更小对象。若较小对象都满足命题,就推出 也满足;等价地说,若 失败,至少有一个更小对象也得失败。
得到 不是反例或存在更小反例的矛盾,于是 只能为空,原命题对整个论域成立。
构造情形设 ,其中 、。归纳假设是 :对每个字符串 ,都有 。
对任意 ,由连接的构造规则,;再由长度的构造规则,。
使用归纳假设把 换成 ,得到 。因此 成立。
基础对象与唯一构造规则都已覆盖,所以由结构归纳,等式对所有 成立。
进一步说,因为值域被限定为 ,反复使用等式还会迫使同一奇偶类上的函数值不断减去 ,最后变成负数。所以这不只是一个低效算法,而是根本没有定义出满足条件的全函数。