谈谈递归


1)递归是一种调用自身的编程技术,能够进行递归编程的关键是能够以递归的方式进行思考

2)任何递归的定义都必须包含一个称为基本条件的非递归部分,是递归最终能够终止,否则会导致无穷递归

3)递归编程:方法的每次递归调用都将创建新的局部变量和参数

4)在某些情况下,迭代方法显得极为复杂,对于某些问题,递归能够创建简短,高效的程序。

5)间接递归是指一个方法调用另一个方法,另一个方法又调用自己。或者嵌套更多层。


一个迷宫的例子:

用一个矩阵抽象表示迷宫,1,0表示可通过与不可通过,用递归来从迷宫的任意点搜索是否有到达终点(右下角为出口)的路径

 
  
package DiGui;

public class MazeSearch {

public static void main(String[] args) {

Maze maze
= new Maze();

System.out.println(
" the grid is : " );
System.out.println(maze);
// 自动调用toString方法

if (maze.successFrom( 0 , 0 ))
System.out.print(
" There is a path " );
else
System.out.println(
" There is no path!!! " );

System.out.println(
" the path marked is: " );
System.out.println(maze);
}
}



class Maze{

private final int TRIEDFAILD = 4 ; // 将尝试过但没有成功的位置置为4
private final int PATH = 6 ; // 将成功路径上的位置置为6

private int [][] grid = { // 迷宫的矩阵表示
{ 1 , 0 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 },
{
1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 1 },
{
0 , 0 , 0 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 0 },
{
0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 },
{
0 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 0 , 1 , 1 , 1 , 1 },
{
0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 },
{
1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 },
{
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 },
};


public boolean valid( int row, int column){ // 某个位置是否为1,只有为1才有可能是通路
boolean result = false ;
if ((row >= 0 && row <= grid.length) && (column >= 0 && column <= grid[ 0 ].length))
if (grid[row][column] == 1 )
result
= true ;
return result;
}


public boolean successFrom( int row, int column){ // 从点(row,column)位置能否找到通路
boolean done = false ;
if (valid(row,column))
{
grid[row][column]
= TRIEDFAILD; // 为1就先置为尝试过

if (row == grid.length - 1 && column == grid[ 0 ].length - 1 ) // 递归结束条件
done = true ;
else // 递归的过程就在这,向下,右,上,左四个方向上按顺序递归(要防止数组越界)
{
if (row < grid.length - 1 )
done
= successFrom(row + 1 ,column);
if (column < grid[ 0 ].length - 1 )
if ( ! done) done = successFrom(row,column + 1 );
if (row > 0 )
if ( ! done) done = successFrom(row - 1 ,column);
if (column < grid[ 0 ].length)
if ( ! done) done = successFrom(row,column - 1 );
}
if (done)
grid[row][column]
= PATH; // 如果通过了就继续将尝试过升级为成功
}
return done;
}


public String toString(){ // 打印出通过之后的标记数组
String result = " \n " ;
for ( int row = 0 ;row < grid.length;row ++ )
{
for ( int column = 0 ;column < grid[row].length;column ++ )
result
+= grid[row][column] + "" ;
result
+= " \n " ;
}
return result;
}

}



执行结果:(用6替代原来的1标记一条通路,用4标记原来的1标记尝试过但最后没有路退回来的位置)

2011042222361740.jpg


看了下书,写了个迷宫的小程序,其基本的思想就是,如果从一某个点能找到一条出路,那么从这个点的四个邻居点就一定至少有一个能找到出路,这样就去递归的找它的邻居点的路线。



--------------------------------------------------------------------------------------------------------------------------------------------------                        这是分割线,下面是别人的文章

--------------------------------------------------------------------------------------------------------------------------------------------------


下面是到bbs上找了几篇别人写的谈递归的文章:摘录精彩部分---

--------------------------------------------------------------------------------------------------------------------------------------------------

对一个输入的整数n,输出时从最低位开始每3位加上','。 
如输入:12345678 
输出:12,345,678 


想法一:把输入n的每一位都放在数组里面,然后看一共有多少位,把高几位(可能是1,2,3)输出出来,加上',',然后每输出3位数字之后输出一个',',当然还要考虑最低3位之后不用输出','。 

想法二:利用一个字符堆栈,不断的把最低位的字符n%10+'0'压入堆栈,每压入3个就压入一个',',n/=10,一直这样做下去,直到n为0,最后出栈,输出一个一个字符。 

想法三:n有多少位,假设有m位,那么可以先把前m-3位按照本题的方式输出,加上一个',',再输出最低3位,就完成了(!!以递归的方式思考问题。假设按本方式输出的一个函数为print(),则它可以这样定义: 
print(n){ 
print(n/1000);//n/1000为前m-3位 
输出','; 
输出后3位;//后3位为n%1000 


说说3种方法的优劣:想法一,考虑的细节比较多,容易出错,写起来憋屈;想法二和三,思路很清晰,二实现起来需要先实现1个堆栈,三则用了递归,自己写起来工作量少,憋屈给了计算机。 

按照方法三写了一下 
void print(int n){ 
if(n/1000>0){ 
print(n/1000); 
cout<<',';

         cout<<n%1000; 


输入1234,看见屏幕上出现1,234 


心里爽了一下,但是这里面有问题,当我们输入1000的时候,会输出1,0,为什么呢?看了下,原来我们输出n%1000,只是输出了n%1000的值而已,并不是把每一位都输出 
作出如下修改: 
void print(int n){ 
if(n/1000>0){ 
print(n/1000); 
cout<<',';

         cout<<(n%1000)/100; 
cout<<((n%1000)/10)%10; 
cout<<(n%1000)%10; 

分别输出百位十位个位上的数字,心想这下可好了,每位都输出了。 

兴奋的输入1000,发现屏幕上显示出001,000 
这倒是对了,可是最前面的1也变成了001,我们需要省略高位的0,经过思考,变成一下版本: 
void print(int n){ 
if(n/1000>0){ 
print(n/1000); 
cout<<',';

else{ 
cout<<n; 
return; 

         cout<<(n%1000)/100; 
cout<<((n%1000)/10)%10; 
cout<<(n%1000)%10; 

解释一下,因为当n/1000>0不成立的时候,说明现在要输出的n<1000,只用直接把n输出就好了,并且返回。 

到这里差不多了,总结一下这个例子带给我的启发 
使用递归,首先在逻辑上把问题划分成规模小的几个部分,其中有些部分的解法和本问题一样,然后写出大致的逻辑上的表示,第一部分怎么做,第二部分怎么做,一直到最后一部分,最后处理问题的细节。抛砖引玉,希望大家也说说自己的见解。 


以上by   ark@BMY  bbs

--------------------------------------------------------------------------------------------------------------------------------------------------

将复杂的处理归纳为较简单的处理,直到 最简单的处理。 
基础为归纳,即通过观察,得到3个内容: 1、递归的形式; 
                   2、最基本式是否有解决的方案; 
                   3、递归终止的条件 例子 

1 某人写了n封信和n个信封,如果所有的信都装错了信封。求所有的信都装错信封共有多少种不同情况。 归纳法例子 1.有n个硬币(n为偶数)正面朝上排成一排,每次将n-1个硬币翻成朝上为止。编程让计算机把翻硬币的最简过程及翻币次数打印出来(用*代表正面,用0代表反面)。 
基本形式:D[1]=0;d[2]=1 
递归式:d[n]= (n-1)*( d[n-1] + d[n-2]) 

3 梯有N阶,上楼可以一步上一价,也可以一次上二阶。编一个程序,计算共有多少种不同的走法。 
递归的形式:s[n]=s[n-1]+s[n-2] 
基本式子:s[1]=1;s[2]=2 


以上by  macintosh  @BMY bbs


------------------------------------------------------------------------------------------------------------------------------------------------





转载于:https://www.cnblogs.com/jmzz/archive/2011/04/22/2025331.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值