共有回帖数  0  个 
	 
	
	
	
     
          
          
               
				
			 
				
					 
 
            
				   - 
						
						
							 
									众所周知,递归是一种重要的方法,我对递归可谓是一窍不通,至今没破……
 Recursion is the name for the case when a function invokes itself or invokes a sequence of other functions,one of which eventually invokes the first function again.
 递归就是一个函数调用自身或者调用一系列的函数,其中某个函数又调用了第一个函数。书上就是这么写的,我不知道我翻译的准不准确。
 介绍递归最主要就是介绍栈帧和递归树,栈帧也叫过程活动记录,是编译器用来实现过程或函数调用的一种数据结构。从逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。
 举个例子:假如我们有三个函数分别叫做A、B和C,假设A调用B,B调用C,所以当函数C没有完成并返回时函数B不会完成,这样,函数A最先被调用但是是最后一个完成,直到B完成并返回后A 才会完成,用栈帧来表达就是这样——
  
 
  
 
  
 首先让我们先来了解一下简单的递归应用:阶乘
 int factorial(int n)//求n的阶乘
 {
 if(n==0)
 return 1;//返回0的阶乘为1;
 else
 return n*factorial(n-1);//返回n的阶乘为n*(n-1)!,factorial通过调用自身实现递归
 }
 我们在来看一个比较简单的递归应用:求第n个fibonacci数
 所谓的fibonacci数列指的是第零个数为0,第一个数为1(这里为了与后面对应所以第一个数称为第零个),从第三个数开始每个数都是它之前两个数的和,即: f0=0;f1=1;f2=f0+f1=1;f3=f2+f1=3……
 第n个fibonacci数也就是fn,应该等于f(n-2)+f(n-1),所以我们能写出程序:
 int fibonacci(int n)
 {
 if(n=0)
 return 0;
 else if(n==1)
 return 1;
 else
 return fibonacci(n-2)+fibonacci(n-1);
 }
 递归的经典应用:汉诺塔问题——有三根柱子A、B、C,柱子A由下到上有从大到小n个盘子,编号从上到下为1到n,要把这n个盘子利用柱子B全部移动到柱子C上,每次只能移动一个盘子并且要保证上面的盘子一定比下面的盘子小。
 对于这个问题,我们首先是要把最下面的盘子n移动到柱子C上,这样就要求把上面的n-1个盘子利用柱子C移动到柱子B上面,然后我们又要把上面n-2个盘子从柱子B利用柱子C移动到柱子A上使第n-1个盘子能够移动到柱子C上,然后是柱子A上的n-3个盘子移动到柱子B上把第n-2个盘子移动到柱子C上……以此类推,一直到只剩盘子1,把盘子1移动到柱子C上。
 根据上面的思路我们可以写出程序:
 #includeiostream
 using namespace std;
 void hanio(int n,char,char,char);
 void main()
 {
 char A='A',B='B',C='C';
 int n=3;
 hanio(n,A,B,C);
 }
 void hanio(int n,char A,char B,char C)
 {
 if(n==1)
 {
 cout"将第"n"个盘面从"A"柱搬到"C"柱上"endl;
 }
 else
 {
 hanio(n-1,A,C,B);
 cout"将第"n"个盘面从"A"柱搬到"C"柱上"endl;
 hanio(n-1,B,A,C);
 }
 }
 运行结果是:将第1个盘面从A柱搬到C柱上,将第2个盘面从A柱搬到B柱上,将第1个盘面从C柱搬到B柱上,将第3个盘面从A柱搬到C柱上,将第1个盘面从B柱搬到A柱上,将第2个盘面从B柱搬到 C柱上,将第1个盘面从A柱搬到C柱上
 科学计算表明,解决有n个盘子的汉诺塔问题,需要移动盘子的次数为2的n次方减1次。
 下面我们来说回溯算法,所谓回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
 回溯法的经典问题有“八皇后问题”——在8*8的棋盘上放置8个皇后而彼此不受攻击(即在棋盘的任一行,任一列和任一对角线上不能放置2个皇后)这个问题我也不很明白,把代码发上来,大家自己研究吧
 这里感谢开源中国G0561的代码:
 /*
 回溯法是 按照某种条件往前试探搜索,若前进中遭到失败,则回过头来继续搜索
 
 回溯的设计:
 1. 用栈保存好前进中的某些状态
 2.制定好约束条件
 */
 #includeiostream
 using namespace std;
 void Queen(int j,int (*a)[8]); //递归搜索试探放置皇后
 int Judge(int i,int j,int (*a)[8]); //判断在a[j]是否可以放置皇后 int ncount = 0;
 int main()
 {
 int i,j;
 int a[8][8] = {0};
 
 
 Queen(0,a);
 coutncountendl;
 system("pause");
 return 0;
 }
 ///////////////////////////////////////////////////////////
 void Queen(int j,int (*a)[8])
 {
 int i,k,;
 
 if (j==8) //递归结束条件
 {
 ncount++;
 //打印正确的放置
 for (i=0; i8; i++)
 {
 for (k=0; k8; k++)
 {
 couta[k]" ";
 }
 coutendl;
 }
 getchar(); //按一个确认键看下一个,可看到所有排列
 coutendl;
 }
 
 for (i=0; i8; i++)
 {
 if (1==Judge(i,j,a)) //判断当前格子是否可以放置皇后
 {
 a[j] = 1; //放置皇后
 
 Queen(j+1,a); //向下一列试探是否可以放置皇后
 
 a[j] = 0; //回溯到上一步
 }
 else
 {
 continue;
 }
 }
 }
 ///////////////////////////////////////////////////////////
 int Judge(int i,int j,int (*a)[8]) //判断在a[j]是否可以放置皇后
 {
 int s,t;
 
 for (s=i,t=0; t8; t++ ) //判断行
 {
 if (a[s][t]==1 && t!=j)
 {
 return 0;
 }
 }
 
 // 判断列
 for (t=j,s=0; s8; s++)
 {
 if (a[s][t]==1 && s!=i)
 {
 return 0;
 }
 }
 
 //判断左上斜
 for (s=i-1,t=j-1; s=0&&t=0; s--,t--)
 {
 if (a[s][t] == 1)
 {
 return 0;
 }
 }
 
 //判断右上斜
 for (s=i-1,t=j+1; s=0&&t8; s--,t++)
 {
 if (a[s][t] == 1)
 {
 return 0;
 }
 }
 
 //判断左下斜
 for (s=i+1,t=j-1; s8&&t=0; s++,t--)
 {
 if (a[s][t] == 1)
 {
 return 0;
 }
 }
 
 //判断右下斜
 for (s=i+1,t=j+1; s8&&t8; s++,t++)
 {
 if (a[s][t] == 1)
 {
 return 0;
 }
 }
 return 1;
 }
 本人新菜一个,语言表达不清楚,图画的也不是很准确,请大神轻喷~
 
 
 楼主 2016-04-28 11:09 回复 
 
 
   
             
                  
                  
 
 
 
     
	 
  
	Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
	
	意见反馈 | 
	关于直线 | 
	版权声明 | 
	会员须知