谈谈递归
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标记尝试过但最后没有路退回来的位置)
看了下书,写了个迷宫的小程序,其基本的思想就是,如果从一某个点能找到一条出路,那么从这个点的四个邻居点就一定至少有一个能找到出路,这样就去递归的找它的邻居点的路线。
-------------------------------------------------------------------------------------------------------------------------------------------------- 这是分割线,下面是别人的文章
--------------------------------------------------------------------------------------------------------------------------------------------------
下面是到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
------------------------------------------------------------------------------------------------------------------------------------------------