CPP:把for改写成递归形式的小技巧()

        前言:考试的时候(或者平常)可能都会遇到DFS啦各种递归啦之类的算法。我们老师说的好:只要你会了for和DFS,就能拿省一。于是我就开始思考DFS和for之间的关系,总结了一下改写的小技巧。

简单介绍:

        for循环其实绝大部分可以改写成递归形式,在不考虑空间复杂度的形况下,把for改写成递归形式的好处就是可以很方便的调试代码(不然你发现你代码写错了,拖着一撮for上下乱跑,大括号你都对应不起来了就),还能便捷的把for改成n层for(forrer,比for还for)

        比如,我下面写下一个简单的for的代码来求前缀和->

#include<iostream>
#include<cstdio>
using namespace std;
int sum=0;
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		printf("%d",sum); 
		sum+=i;
		printf("加上%d之后是 %d\n",i,sum);
	}
	printf("%d",sum);
	return 0;
}

运行结果如下:

        那么我怎么给他改写成递归形式呢?来看for里面,一个printf,一个求和,一个printf。我们需要什么?只需要递归往下加数就行了啊。接下来开始想怎么写代码。

        万物之源归于定义:void forrer(int k);

         为什么要定义一个k呢?这里面的k就相当于是for里面的i,也就是作为加数。

        接下来考虑怎么写。递归,都要有结束条件,for的结束条件来自于第二个参数是否为真,上面的例子里面,for的第二个参数是i<=n,也就是k的结束条件是k>n的时候结束而在k<=n的时候继续执行。

void forrer(int k){
	if(k==n){
		sum+=k;
		return;
	}
}

//或者下面形式

void forrer(int k){
	if(k>n) return;
}

        接下来要做的就是抄代码了。我可以完全把for里面的内容照搬下来,变成下面这样。

void forrer(int k){
	if(k>n) return;
	printf("%d",sum);//先打印sum 
	sum+=k;//求和 
	printf("加上%d之后是 %d\n",k,sum);//再打印sum 
	forrer(k+1);//让“for”进入下一层 
}

        运行结果和for完全相同。

        递归形式中的递归下一层,可以理解为for里的第三个表达式。

到了现在,for改写成了递归形式,我们总结一下知识点:

        1.for(int i=1;i<=n;i++) 中int i对应递归中的void forrer(int k)

        2.递归开始的初始值相当于for里的第一个表达式,上例的forrer(1) == for(i=1;..;..);

        3.递归里的返回条件是for里面i<=n的补集;

        4.递归里进入下一层的条件对应for里面的i++;

        5.递归里的处理代码直接照搬for里面代码。

for循环嵌套怎么改写?

例子:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			printf("i = %d ; j = %d\n",i,j); 
		}
	}
	return 0;
}

运行结果:

 

        你会发现for循环嵌套了哎233。而且第二个表达式还不一样,要知道,上面第一个例子的for到n终止,在递归里就可以到相应的位置直接停止,但是这次有两个循环次数,而我只想用一个递归怎么办。

思考一个问题,为什么递归里可以直接写入 if(k>n) return;

         就是因为只循环了n次,但是我这次需要内部额外循环的截止条件是个变量怎么办,很简单,函数嘛,里面可以传N多参数。再开一个参数记录次数,这里不是循环次数,而是类似i,j一样的才能在,就完了。

        因此可以这么改:

void forrer(int i,int j){
	if(i>n) return;
	if(j>m){
		forrer(i+1,1);
		return;
	}
	printf("i = %d ; j = %d\n",i,j); 
	forrer(i,j+1);
}

        首先祖传返回写最上面,实现抄在下面,遍历最内层变量,到边界就遍历第二层。因此三层for循环可以这么改:

void forrer(int i,int j,int k){
	if(i>n) return;
	if(j>m){
		forrer(i+1,1,1);
		return;
	}
	if(k>o){
		forrer(i,j+1,1);
		return;
	}
	printf("i = %d ; j = %d ; k = %d\n",i,j,k); 
	forrer(i,j,k+1);
}

        在知道循环次数的条件下,可以随便搞。

        那么新的问题就是,我不知道循环嵌套了几层怎么办(DFS),比如说,我输入了一个n,要求n层for循环,每层循环n次(复杂度N^N,N=11就会炸),这里有个问题(不是全排列),描述如下:

        输入一个N;

        要求有N层for循环,每层循环N次;

        输出遍历顺序;

        代码如下:

int arr[114514];
void forrer(int k){
	for(int i=1;i<=n;i++){
		arr[k]=i;
		if(k==n){
			for(int j=1;j<=n;j++) cout<<arr[j]<<" ";
			cout<<endl;
		}
		else forrer(k+1);
	}
}

只需要告诉函数一共有几层,就可以跑出来了。

        而且,你在应用最上面的转换代码的时候,如果有10层for循环,总不能传入10个参数吧。用这种形式则可以方便的把3层for循环改写成下面的代码:又方便,又适合修改任何一层的内容(建议背下来)

int arr[114514];
void forrer(int k){//k表示第k层
	for(int i=1;i<=3;i++){
		arr[k]=i;
		if(k==3){
			for(int j=1;j<=3;j++) cout<<arr[j]<<" ";
			cout<<endl;
		}
		else forrer(k+1);
	}
}

感谢​  @神再佑我長龍​​​​​​  提供的一小点思路

​​​​​​​

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值