递归是一种编程技术,它在计算机科学中被广泛应用,尤其是在解决问题时通过将大问题分解为规模较小的相同问题来实现。在给定的代码片段中,`queen` 函数是一个经典的递归示例,用于解决八皇后问题,即在给定的棋盘上放置皇后,使得任意两个皇后都不在同一行、同一列或对角线上。这个函数通过递归地尝试将皇后放置在每一行的不同列上,并在完成当前行后继续处理下一行,直到所有行都放置了皇后。
函数的递归过程如下:
1. 递归定义:
- `queen(int k, int n)` 函数接收两个参数,`k` 表示当前考虑的行号,`n` 表示总共的行数。当`k` 大于`n`时,表示已经处理完了所有行,此时输出一个解。这是递归的基本终止条件,即无更多行需要放置皇后。
- 如果`k` 小于或等于`n`,则会进入循环。循环遍历从1到`n`的所有列(`j`),在第`k`行的第`j`列检查是否适合放置皇后。如果符合条件(这通常涉及到避免冲突,比如不在同一行、列或对角线上),就在当前位置`(k, j)`放置皇后(`q[k]=j`),然后继续递归调用 `queen(k+1, n)`,处理下一行。
2. 递归调用:
- 函数中的递归调用 `queen(k+1, n)` 是关键,它表示在当前行放置皇后后,继续处理下一行。这是直接递归的一个实例,因为函数本身在其定义中直接调用了自己。
3. 递归的应用场景:
- 数学问题:递归常用于解决数学问题,如计算阶乘(如例子中所示,`fun(n)` 函数用于计算`n!`),或者著名的斐波那契数列,它们都有递归定义。
- 数据结构:递归也用于数据结构的定义,如单链表(如`LinkList`)的定义中,`LNode` 结构包含一个指向自身类型的指针,体现了递归性质。
5.1.2 递归的使用时机:
- 当问题可以自然地分解为相同或相似的子问题时,递归是一个有效的工具。例如,八皇后问题和阶乘计算就是递归问题,因为每个子问题都是原问题的一个缩小版本。
- 对于递归数据结构的处理,如链表的遍历和操作,递归可以使代码简洁且易于理解。
总结起来,递归是一种强大的抽象概念,它通过函数或过程调用自身来解决复杂问题。理解递归的关键在于识别问题的递归结构,设置合适的递归基(终止条件)和递归步骤(子问题)。在实际编程中,合理运用递归能够提高代码的可读性和效率。然而,过度使用或不当设计可能导致性能问题,因此递归设计时需要谨慎考虑。