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