一个递归的陷阱

在学习多线程时学习做一个密码破解小程序,其中在写暴力破解的方法时出现了个递归调用方面的陷阱困扰了我很长时间,特此记下一笔:

场景:写一个3位长度的字符串(数字、大小写字母),通过程序罗列出所有的组合

方法一:

采用多层循环

public static void main(String[] args) {
		char[]  chars = new char[3];
		for(char i='0';i<='z'+1;i++) {
			 if(!Character.isLetterOrDigit(i)) {
				 continue;
			 }
			 chars[0] = i;
			for(char j='0';j<='z'+1;j++) {
				if(!Character.isLetterOrDigit(j)) {
					 continue;
				 }
				chars[1] = j;
				for(char k='0';k<='z'+1;k++) {
					if(!Character.isLetterOrDigit(k)) {
						 continue;
					 }
					chars[2] = k;
					System.out.println(Arrays.toString(chars));
				}
			}
		}
	}

这种嵌套循环的方式可以找出所有组合,但是不容易扩展,例如现在要实现4位或5位的字符串。


现在考虑使用递归的方式解决

方法二:

递归调用

public class PojieThread extends Thread{
	
    private boolean flag = true;
	public void generateWord(char[] chars,String mima, int index) {
		
			if(flag==true) {
				
				for(short i='0';i<='z';i++) {
					Character ch = (char)i;
					chars[index] = ch;
					
					if(index<chars.length-1) {
						generateWord(chars, mima, index +1);
					}else  {
						String str = new String(chars);
						store.add(str);
						System.out.println("插入-"+str);
						if(str.equals(mima)) {
							System.out.println("找到密码---"+str);
							flag=false;
							
						}
					}
					
				}
			}
		
		
	}
}

第一次在实现时,在递归调用的地方写为

                              generateWord(chars, mima, ++index);//错误写法

 这就导致进入下一层的时候把本层的index自增了,也就导致chars[index]在错误的位置赋值,这个问题比较隐蔽,出问题后困扰了很长时间。

第二个问题出现在

if(str.equals(mima)) {
							System.out.println("找到密码---"+str);
							
							return;
						}

我以为return会把这个递归给结束,但发现return只能结束本层循环,代码会返回上层继续执行。 

解决方法:

添加全局的布尔变量做知否递归循环的标记

 

 

<think>好的,用户问的是关于Python中递归的最后一个问题。首先,我需要明确用户的具体需求是什么。用户提到了“递归的最后一个”,可能是指递归的终止条件,或者递归过程中的最后一个步骤,或者是递归调用栈中的最后一个函数调用。 先回顾之前的对话历史,用户之前询问了如何在print时跳过None值,我给出了几种方法。现在用户转向递归的问题,可能是在学习递归时遇到了困难,特别是关于递归终止条件或递归的结束部分。用户可能对递归的工作原理不太清楚,尤其是在递归如何结束以及如何确保递归正确终止方面存在疑问。 接下来,我需要确定“递归的最后一个”具体指什么。在递归中,终止条件(base case)是至关重要的,它防止无限递归。另一个可能性是尾递归(tail recursion),虽然Python并不优化尾递归,但用户可能对此感兴趣。此外,用户可能想知道递归调用栈中的最后一个步骤,即递归展开时的最后一步操作。 考虑到用户可能是初学者,需要以简单明了的方式解释递归的基本结构,尤其是终止条件的重要性。可能需要举例说明,比如阶乘或斐波那契数列,来展示如何设置终止条件,并确保递归正确结束。 同时,用户可能对递归的执行过程有疑问,比如递归调用栈是如何工作的,最后一次递归调用后如何回溯。需要解释递归的展开和回溯过程,强调如果没有适当的终止条件会导致栈溢出错误。 另外,用户可能在编写递归函数时遇到了问题,比如忘记设置终止条件,或者终止条件设置不正确,导致函数无法正常结束。这时候需要给出示例代码,说明正确的终止条件如何设置,以及错误的情况是怎样的。 还要考虑用户可能的误解,比如认为递归的最后一个步骤会有特殊的处理,但实际上每次递归调用都是独立的,直到达到终止条件才开始返回结果。需要澄清递归的执行流程,确保用户理解每一步递归调用都是独立的实例。 最后,总结递归的关键点,强调终止条件的必要性,递归调用的正确方式,以及可能遇到的常见错误和解决方法。通过示例和分步骤的解释,帮助用户建立正确的递归思维,避免常见的陷阱。</think>在 Python 中,**递归的最后一个步骤**通常指递归函数中的 **终止条件(Base Case)**,它是递归能够正常结束并避免无限循环的关键。以下从原理到实践详细说明: --- ### 一、递归的核心结构 递归函数必须包含两部分: 1. **终止条件**(Base Case) - 当满足条件时,直接返回结果,不再递归 - 若无终止条件,会触发 `RecursionError: maximum recursion depth exceeded` 2. **递归步骤**(Recursive Step) - 将大问题拆解为小问题,调用自身处理子问题 --- ### 二、终止条件的典型场景 #### 示例1:阶乘计算 ```python def factorial(n): # 终止条件:n=0 或 n=1 时直接返回1 if n <= 1: return 1 # 递归步骤:n! = n * (n-1)! return n * factorial(n-1) ``` - **终止条件**:当 `n <= 1` 时结束递归,返回 `1` - **递归步骤**:将问题转换为 `n * factorial(n-1)` #### 示例2:斐波那契数列 ```python def fibonacci(n): # 终止条件:n=0 或 n=1 时返回对应值 if n == 0: return 0 elif n == 1: return 1 # 递归步骤:fib(n) = fib(n-1) + fib(n-2) return fibonacci(n-1) + fibonacci(n-2) ``` --- ### 三、递归的"最后一个步骤"如何工作? 以 `factorial(3)` 为例,递归调用栈展开如下: 1. `factorial(3)` 调用 `3 * factorial(2)` 2. `factorial(2)` 调用 `2 * factorial(1)` 3. **终止条件触发**:`factorial(1)` 返回 `1` (这是递归的最后一个步骤) 4. 逐层回溯计算: - `factorial(2)` 返回 `2 * 1 = 2` - `factorial(3)` 返回 `3 * 2 = 6` --- ### 四、递归深度与优化 1. **默认递归深度限制** Python 默认递归深度约为 1000(可通过 `sys.getrecursionlimit()` 查看) 2. **尾递归优化(Python不支持)** - 理论上可将递归改写为循环形式以避免栈溢出 - 例如阶乘的尾递归改写: ```python def factorial_tail(n, accumulator=1): if n <= 1: return accumulator return factorial_tail(n-1, n * accumulator) ``` - 但 Python 解释器不会优化尾递归,仍会占用栈空间 --- ### 五、常见错误与解决方法 | 错误类型 | 示例代码 | 修正方案 | |---------|---------|---------| | 缺少终止条件 | `def f(x): return f(x-1)` | 添加终止条件如 `if x == 0: return` | | 终止条件未触发 | `def f(x): if x < 0: return; return f(x-1)` | 确保参数变化最终满足终止条件 | | 未正确处理返回值 | `def f(n): if n==0: return; return n + f(n-1)` | 明确终止条件的返回值 | --- ### 六、总结 - **终止条件是递归的“安全阀”**:必须确保所有递归路径最终能触发终止条件 - **递归本质是栈操作**:每次递归调用会压栈,返回时逐层弹栈计算 - **优先考虑循环替代**:对于深度大或性能敏感的场景,建议改用迭代(循环)实现 通过合理设计终止条件和递归步骤,可以高效解决分治、树遍历等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值