递归

本文介绍了递归算法的基本思想及应用,包括汉诺塔问题、查找数组最大值、折半查找法等经典案例。详细解释了如何建立递归模型,确定基例与执行步骤。

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

        递归算法采用了分而治之的思想,将复杂的问题分解为小的问题,并且这个小的问题的类型与原始问题的类型完全相同。通过分解,最终原始问题变得非常小,其解决方案显而易见,或为已知。那么对此类问题应怎样建立递归模型呢。

       1,分析问题:确定问题能否分解为一个更小的问题,并且小的问题的类型和原始问题类型相同。确定该问题的循环不变式(loop invariant).

       2,确定基例:当把问题分解的足够小时,即其最小问题的解决方案显而易见或者已知,即寻找到了此问题的基例。将基例作为解决问题的最小条件,由此条件而逐级回溯从而解决问题。
       3,执行步骤:将一级小问题视为已知完全求解,则此原始问题的解决方案很容易确定,由此确定解决方案的执行步骤。
      4,参数确定:递归函数的参数可分为四类:源因子,控制因子,接收因子和行为因子。具体问题具体分析,确定其需要的参数因子。
实例分析
       hanoi塔
       hanoi塔大家都已经熟知,在这里我就不多说了,直入正题。
      初始状态时,所有的圆盘都在A上,目的是将A上的圆盘全部移到B上,那么将A上的n-1、n-2 个圆盘放在B上与将A上的所有的圆盘都放在B上类型相同,即可确定采用递归算法。当盘的数目为0或者为1时可确定达到基例,其无需进行操作或者将一个盘移到由A移到B上。将A盘上n-1个圆盘操作视为已完成的整体(即可一次性将其移到B或C盘)。完成原始问题的解决方案确定为,将A上n-1个圆盘移到C上,然后将A上的最后一个移到B上,然后再将C盘上的n-1个圆盘移到B上,则完成所有操作。
        参数选择时把N作为源因子,‘A’ ‘B’ ‘C’作为表示操作的行为因子。则其函数表达式为:
void sethan1(int count,char source,char destination,char medium)
{
	if(count==1)
		cout<<"Move top disk from pole "<<source<<" to pole "<<destination<<endl;
	else
	{
		sethan1(count-1,source,medium,destination);
		sethan1(1,source,destination,medium);
		sethan1(count-1,medium,destination,source);
	}
}
或
void sethan2(int count,char source,char destination,char medium)
{
	if(count>0)
	{
		sethan2(count-1,source,medium,destination);
		cout<<"Move top disk from pole "<<source<<" to pole "<<destination<<endl;
		sethan2(count-1,medium,destination,source);
	}
}
查找数组最大项:
       在数组Array中查找最大项,分解数组为两个部分,分别找出最大项然后进行比较,取最大值。当分解的数组只有一项时,则其最大值即为该唯一项,由此可确定基例。
将数组的两个部分分别视作已完成的整体(即分别取得两个部分的最大值),然后进行比较,取最大值返回。

       参数选择时,把arr作为源因子,first last作为控制因子。则其函数表达式为:

int searchMax1(int arr[],int first,int last)
{
	if(first>=last)
		return arr[first];
	else
	{
		int mid=(first+last)/2;
		return max(searchMax1(arr,first,mid),searchMax1(arr,mid+1,last));
	}
}

int searchMax2(int arr[],int first,int last)
{
	if(first>=last)
		return arr[first];
	else
	{
		int mid=(first +last)/2;
		if(searchMax2(arr,first,mid)>=searchMax2(arr,mid+1,last))
			return searchMax2(arr,first,mid);
		else
			return searchMax2(arr,mid+1,last);
	}
}

折半查找法
在已排序的数组array中查找指定值,分解数组为两个部分,判断指定值位于哪个部分,然后再将指定值所在的部分数组进行分解。
当分解的数组中只含有一项时,达到基例或者只含有一项时并且与指定值不相等时为基例(因为这是一个返回值函数,当存在指定值时已经返回,不存在指定值可作为基例)。
将数组的两个部分分别视作已完成的整体(具有返回值,或找到或找不到),返回由判断可知的那部分数组。

参数选择,传递一个源因子,first last 作为控制因子,则其函数表达式为:

  

int binarySearch(int arr[],int first,int last,int key)
{
	if(first>last)
		return -1;
	else
	{
		int mid=(first+last)/2;
		if(arr[mid]<key)
         		return binarySearch(arr,mid+1,last,key);
	        else if(arr[mid]==key)
	        	return mid;
             	else
	         	return binarySearch(arr,first,mid-1,key);
	}
}


  查找第k最小项:

         这个我理解的不到位就不多说了。函数表达式为:

//using the first item as the pivot and sort the array arr which is satisfy //for first part region items smaller than pivot and second part region 
//items equal or bigger than pivot. 
//look for the pivot P,and return it's position in arr;
//the return value is absolute

int findP1(int arr[],int first,int last)
{
	int lastS1=first;//lastS1 stands for S1 region's last position.
	int firstUn=first+1;//fisrt stands for unknown region's first position.
	while(firstUn<=last&&first<=last)
	{
		if(arr[first]<=arr[firstUn])
			firstUn++;
		else
		{
			int temp=arr[lastS1+1];
			arr[lastS1+1]=arr[firstUn];
			arr[firstUn]=temp;
			lastS1++;
			firstUn++;
		}
	}
	return lastS1;
}

//the return value is relative
//and reset pivot in "right "position .
int findP2(int arr[],int first,int last)
{
	int lastS1=first;
	int firstUn=first+1;
	int temp;
	while(firstUn<=last)
	{
		if(arr[first]<=arr[firstUn])
			firstUn++;
		else
		{
			temp=arr[lastS1+1];
			arr[lastS1+1]=arr[firstUn];
			arr[firstUn]=temp;
			lastS1++;
			firstUn++;
		}
	}
	temp=arr[first];
	arr[first]=arr[lastS1];
	arr[lastS1]=temp;
	return lastS1-first;
}

//the return value is absolute,
//and reset the pivot in "right "position.
int findP3(int arr[],int first,int last)
{
	int lastS1=first;
	int firstUn=first+1;
	int temp;
	while(firstUn<=last)
	{
		if(arr[first]<=arr[firstUn])
                	firstUn++;
		else
		{
		        temp=arr[lastS1+1];
			arr[lastS1+1]=arr[firstUn];
			arr[firstUn]=temp;
			lastS1++;
			firstUn++;
		}
	}
	temp=arr[first];
	arr[first]=arr[lastS1];
	arr[lastS1]=temp;
	return lastS1;
}


int kSmall1(int k,int arr[],int first,int last)
{
	int p=findP1(arr,first,last);
	if(k<p-first+1)
		return kSmall1(k,arr,first+1,p);
	else if(k==p-first+1)
		return arr[first];
	else
		return kSmall1(k-p+first-1,arr,p+1,last);
}
int kSmall2(int k,int arr[],int first,int last)
{
	int p=findP2(arr,first,last);
	if(k<p+1)
		return kSmall2(k,arr,first,p-1+first);
	else if(k==p+1)
		return arr[p+first];
	else
		return kSmall2(k-p-1,arr,first+p+1,last);
}
int kSmall3(int k,int arr[],int first,int last)
{
	int p=findP1(arr,first,last);
	if(k<p+1)
		return kSmall3(k,arr,first+1,p);
	else if(k==p+1)
		return arr[first];
	else
		return kSmall3(k,arr,p+1,last);
}
int kSmall4(int k,int arr[],int first,int last)
{
	int p=findP3(arr,first,last);
	if(k<p+1)
		return kSmall4(k,arr,first,p-1);
	else if(k==p+1)
		return arr[p];
	else
		return kSmall4(k,arr,p+1,last);
}

reference

              《Data Abstraction and Problem Solving wiht c++ 》(Fourth Edition)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值