递归的思考

本文探讨了递归的概念,对比了递归与迭代的优缺点。递归虽然思路清晰、程序简洁,但效率较低,适合于问题的逐步求解。递归函数通常包括终结情况和递归步骤,尾递归可以转换为循环。正确性分析涉及递归函数的定义和递归过程的回溯验证。文章通过多个例子展示了如何分析和设计递归函数,强调了函数声明在递归设计中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

理论上的概念

  • 1.函数的主要成分是一个循环,则此种解法叫做迭代,而当函数是通过不断调用自己解决问题的,那么此种解法就叫做递归。
  • 2.递归既浪费时间,又浪费空间,所以递归的效率很低,在要求高性能、低内存的算法上递归不适用。要转换为迭代方法。
  • 3.在迭代函数中必须有程序员自己完成的工作(参数入栈,出栈,转移,返回等)在递归函数中交由系统啦实现。通过隐藏某些实现细节,用时间和空间代价减少了程序设计的工作量,总的来说就是递归思路清晰,程序简洁。
  • 4.尾递归是完全可以转换为while循环实现的,因为尾递归就相当于在程序的尾部把递归函数用程序不断替代,while完全可以实现。
  • 5.递归函数内部一般由两部分定义,第一部分是终结情况,第二部分是递归步骤。
  • 6.递归程序中的递归部分对本层次的程序功能不产生影响(如果递归函数中没有引用传递),分析程序的功能时对其中的递归部分可以只意会,不深究。

求解递归问题的心得:

1某些问题的求解,递归函数设计的正确性很大程度上取决于函数申明的设计(函数的参数以及函数的意义的定义)如hanoi问题。这种问题貌似在函数体中直接应用递归定义,就可以方便的实现递归过程,得到结果。

2.还有一些问题,递归方法比较复杂,函数体中不单纯的只有递归的存在。递归在函数体中只是作为解决方法的一个步骤(只是一小段代码)。求解问题的思想是逐步的,递归只是能够更好的实现这种逐步求解,例如8皇后问题。

递归程序分析

1.通过递归求a数组中的最大值(求a中的最大值,可以先求a左边的最大值la,在求a右边的最大值ra,a的最大值就是la和ra中的最大者)
int max(int* a, int s,int e)
{
	if(s==e)
		return a[s];
	else if(s+1==e)
		return max(a[s],a[e]);
	else
	{
		 int t=(s+e)/2;
		 int ta=max(a,s,t);
		 int tb=max(a,t+1,e);
		 return max(ta,tb);//max是math.H中的函数
	}
}

程序的正确性分析:

  • 1.如果ta=max(a,s,t)能够求出(s,t)之间的最大值,同时tb=max(a,t+1,e)也成立,那么程序就是正确的。
  • 2.ta=max(a,s,t)能否求出最大值呢,继续向下递归判断。发现一直递归下去的话,最终的满足终结条件的max递归函数是正确的。则回溯的话发现max(a,s,t)是可以正确返回的。同理tb=max(a,t+1,e)也是可以正确返回的,则1成立,则此程序成立。

2.将一个没有重复字符的字符串输出其所有中可能的排列(函数定义为从输出从pos位置到字符串结束的所有全排列)
void showAll(string s , int pos, int len)
{
	if(pos==len-1)
		cout<<s<<endl;
	else
		for(int i=pos;i<len;i++)
		{
			swap(s[pos],s[i]);
			showAll(s,pos+1,len);
		}
}
程序的正确性分析:

  • 1.如果要是此函数正确,就要保证for循环中的len-1个showAll函数正确。
  • 2.每一个showAll递归调用,直到pos到最后一个字符串末尾,此时showAll是正确的,回溯过程中,由于最后一个是正确的,可以推出倒数第二个showAll正确。由倒数第二层showAll正确,又可以推出倒数第三层showAll正确,最终可以证明此函数中for循环的第一个showAll正确,同理,其他的showAll正确,所有程序正确

3.hanoi问题.(这里可以发现,此函数能够正确的解决问题,完全是由于函数的定义很成功,所以在递归时可以很容易结合终结条件正确递归)
void hanoi(int n,char pa,char pb,char pc)
{
	if(n==1)
		cout<<pa<<"   "<<pc<<endl;
	else
	{
		hanoi(n-1,pa,pc,pb);
		cout<<pa<<"   "<<pc<<endl;
		hanoi(n-1,pb,pa,pc);
	}
}
程序正确性分析:

  • 1.此函数的定义为:将n个盘子从pa借助pb转移到pc上,根据此定义,可见程序的结构是正确的。那么只要函数的这个定义在函数中能够正确实现,此函数即正确。
  • 2.不断递归到最后,发现最后n=1时是能够正确实现程序的定义的,回溯过程与上一例相似,所以回溯也正确。此函数正确!

4.8皇后问题(描述:行、列、斜线都不能出现两个皇后)。遍历第i行的数据,当(i,j)可以作为皇后时,向下遍历i+1行情况,直到遍历到第8行。
void getAQ(int i,int data[][8])
{
	 int tmp[8][8];//可以入栈操作
	 for(int j=0;j<8;j++)
	 {
 		if(data[i][j]==0)
		{
			copy(tmp,data);//data-->tmp,可以保持回溯后每一层数据保持不变
			set(tmp,i,j);//设置j列,(i,j)的斜对角数据为0.
			if(i<7)
				getAQ(i+1,tmp);
			else
			{
				prt(tmp);//打印
				count++;//计数
			}
		}
	}
}

1.此递归函数就和上面的极度不相似,首先,其终止条件if ( i >= 7 )是写在循环内部的,而不是独立的。

2.此递归函数的申明貌似不能很好的说明整个问题的求解方法。问题的求解方法是一个一行一行向下的过程,函数的定义确定了问题的求解方式。而申明形式在此处显得不太重要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值