1)递归是一种调用自身的编程技术,能够进行递归编程的关键是能够以递归的方式进行思考。
2)任何递归的定义都必须包含一个称为基本条件的非递归部分,是递归最终能够终止,否则会导致无穷递归
3)递归编程:方法的每次递归调用都将创建新的局部变量和参数
4)在某些情况下,迭代方法显得极为复杂,对于某些问题,递归能够创建简短,高效的程序。
5)间接递归是指一个方法调用另一个方法,另一个方法又调用自己。或者嵌套更多层。
一个迷宫的例子:
用一个矩阵抽象表示迷宫,1,0表示可通过与不可通过,用递归来从迷宫的任意点搜索是否有到达终点(右下角为出口)的路径
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标记尝试过但最后没有路退回来的位置)
看了下书,写了个迷宫的小程序,其基本的思想就是,如果从一某个点能找到一条出路,那么从这个点的四个邻居点就一定至少有一个能找到出路,这样就去递归的找它的邻居点的路线。
-------------------------------------------------------------------------------------------------------------------------------------------------- 这是分割线,下面是别人的文章
--------------------------------------------------------------------------------------------------------------------------------------------------
下面是到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
------------------------------------------------------------------------------------------------------------------------------------------------