1_递归思想

函数调用及返回

每次函数调用是一个压入栈的过程,当函数运行结束后,会返回到上一个函数中,弹栈。

举例:
调用情况:main()调用A(),A()调用B(),B()调用C()							---> 递进至边界
返回情况:C()执行完回到B(),B()执行完回到A(),A()执行完回到main()			---> 从边界回归到原问题
  • 递归结束条件,递归边界,递归出口
  • 递归调用公式,递归链条,对原问题进行划分时,对子问题和原问题处理的逻辑相似性

一些理解

将原问题划归为子问题,问题规模缩减,但子问题形式与原问题一样,这个子问题通常是通往边界的极限情况。

当还没碰到边界条件时,递归不断通向边界情况。(递归不断推进至边界)
当碰到边界条件时,递归不断返回,问题逐一解决,最后回到原问题。(从边界不断回归至原问题)

一些例子

函数里只有一条递归语句

这种不管是执行过程还是思路都比较好理解

// 输出 0~n 
void f(int n){
	if(n>0){		// 一直 递进到 边界 f(0) 
		f(n-1);		// 然后 不断回归 到 f(n) 
	}
	cout<<n<<endl;
}
// 数组 从 begin下标 求累加和 
int f(int a[],int begin){
	if(begin==a.length)return 0;		//  一直递进到 begin == a.length 
	return f(a,begin+1)+a[begin];
}

即 	对于 f(a,begin)		-->		f(a,begin+1)+a[begin]
  	对于 f(a,begin+1)	-->		f(a,begin+2)+a[begin+1]
  	对于 f(a,length-1)	-->		f(a,length)+a[length-1]
  	f(a,length)			-->		0								出口
采用这样一种思想去递归, 并找到递归边界(出口) ,	 就能很好解决问题。

一样的思路:

// 求和 至 a [end] 
int f(int a[],int end){
	if(end==-1)return 0;		 
	return f(a,end-1)+a[end];
}

判断字符串是否相等:

bool f(String s1,String s2){
	if(s1.length!=s2.length)return false;	
	if(s1.length==0)return true;
	if(s1.charAt(0)!=s2.charAt(0))return false;		// 看 首字母 是否相等 
	return f(s1.substring(1),s2.substring(1));		// 递归 判断子串 
}

函数里有多条递归语句时

二分的思路:

//sum(begin下标 ~ end下标),二分求和  
int f(int a[],int begin,int end){
	if(begin==end)return a[begin];			// 出口 
	int x=f(a,begin,(begin+end)/2)+f(a,(begin+end)/2+1,end);
	return x;
}
不断削减 问题规模 直至 递归边界 (确定是一定可以到达边界的)
底层问题解决掉,不断回归,问题逐层得到解决。

f(a,0,3)为例,探究其内部过程,结果来自 Dev -C++ 调试
在这里插入图片描述

从数组区间 A [begin,end) 中找出最大的两个整数A [x1] 和 A [x2],A[x1] ≥ A[x2]
元素比较的次数,尽可能地少

非递归方法:
void max2(int a[],int begin,int end,int &x1,int &x2){
	if(a[x1=begin]<a[x2=begin+1])swap(x1,x2);		//  初始化 x1 x2 
	for(int i=begin+2;i<end;i++){		// 从 begin+2 处 遍历数组 
		if(a[x2]<a[i]){				// 如果 a[i] 比 a[x2] 还小,  就直接跳过
			if(a[x1]<a[x2=i]){
				swap(x1,x2);
			}
		}
	}
}
递归方法:
void max3(int a[],int begin,int end,int &x1,int &x2){
	if(begin+2==end){									// [begin,end) 区间里只有两个元素
		if(a[x1=begin]<a[x2=begin+1])swap(x1,x2);
		return;
	}
	if(begin+3==end){									// [begin,end) 区间里只有三个元素
		if(a[x1=begin]<a[x2=begin+1])swap(x1,x2);
		if(a[x2]<a[begin+2]){
			if(a[x1]<a[x2=begin+2]){
				swap(x1,x2);
			}
		}
		return;
	}
	int x1l,x2l;max3(a,begin,(begin+end)/2,x1l,x2l);		// 得到左边区间的最大的两个整数 	a[x1l] >= a[x2l]
	int x1r,x2r;max3(a,(begin+end)/2,end,x1r,x2r);			// 得到右边区间的最大的两个整数	a[x1r] >= a[x2r]
	if(a[x1l]>a[x1r]){
		x1=x1l;x2=(a[x2l]>a[x1r])?x2l:x1r;
	}else{
		x1=x1r;x2=(a[x1l]>a[x2r])?x1l:x2r;
	}
}
int main(){
	int a[]={57,4,3,56,78};
	int x1,x2;
	int t1,t2;
	max2(a,0,5,x1,x2);
	max3(a,0,5,t1,t2);
	cout<<x1<<"  max2  "<<x2<<endl;
	cout<<t1<<"  max3  "<<t2<<endl;
}

需要注意的地方

  • 递归边界的严谨性,正确性
  • 确保所有情况最后都要是归结到递归边界,出口上来。
  • 注意 递归逻辑,以及边界出口(类比多股诺米牌,归纳演绎 )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值