转自:http://blog.youkuaiyun.com/justinavril/archive/2008/08/01/2753596.aspx
所谓递归问题,可以分成两部分来理解:一是基本问题,也可以称之为原始问题,比较好解决;二是后续问题,比较复杂,但是和原始问题比较类似,可以调用自身的一个新的副本去解决它。
最简单的可以归为递归问题的就是阶乘,1的阶乘我们知道是1,2的阶乘为2*1=2*1!,而3的阶乘又是3*2!...这样我们就能够知道如何用递归去实现n的阶乘了。
- publicclassFactorial{
- publicstaticintfactorial(intn){
- intresult=0;
- if(n<=1){
- result=1;
- }
- elseif(n>1){
- result=n*factorial(n-1);
- }
- returnresult;
- }
- publicstaticvoidmain(Stringargs[]){
- for(inti=0;i<10;i++)
- System.out.print(factorial(i)+"");
- }
- }
输出:
- 112624120720504040320362880
当然了这是最简单的,也是最好理解的递归例子,但是它揭示了递归的实质:将复杂问题递归为简单问题解决...
我们再来看看稍微复杂点的,也比较有意思,汉诺塔问题:有1,2,3这3个柱子,1号柱子上有n个盘子(盘子由小到大地串在上面,且小盘子永远不能在大盘子下面),以2号柱子为临时存放地,最终将n个盘子移到3号柱子上。将这个问题分析为递归问题,分解出以下三点:
1. 从1号柱子移动n-1个盘子到2号柱子,3号柱子为临时存放点;
2. 从1号柱子将第n个盘子移到3号柱子;
3. 将n-1个柱子从2号柱子移到3号柱子,1号柱子为临时存放点。
请看代码:
- publicclassHanoi{
- publicstaticvoidhanoi(intmovingPans,StringsourcePillar,StringtargetPillar,StringtempPillar){
- if(movingPans==1){
- movePans(1,sourcePillar,targetPillar);
- }
- else{
- hanoi(movingPans-1,sourcePillar,tempPillar,targetPillar);
- movePans(movingPans,sourcePillar,targetPillar);
- hanoi(movingPans-1,tempPillar,targetPillar,sourcePillar);
- }
- }
- publicstaticvoidmovePans(intpanNum,StringsourcePillar,StringtargetPillar){
- System.out.println("Move"+panNum+"form"+sourcePillar+"#to"+targetPillar+"#");
- }
- publicstaticvoidmain(Stringargs[]){
- System.out.println("3个盘子的汉诺塔问题:");
- hanoi(3,"1","3","2");
- System.out.println("5个盘子的汉诺塔问题:");
- hanoi(5,"1","3","2");
- }
- }
输出:
- 3个盘子的汉诺塔问题:
- Move1form1#to3#
- Move2form1#to2#
- Move1form3#to2#
- Move3form1#to3#
- Move1form2#to1#
- Move2form2#to3#
- Move1form1#to3#
- 5个盘子的汉诺塔问题:
- Move1form1#to3#
- Move2form1#to2#
- Move1form3#to2#
- Move3form1#to3#
- Move1form2#to1#
- Move2form2#to3#
- Move1form1#to3#
- Move4form1#to2#
- Move1form3#to2#
- Move2form3#to1#
- Move1form2#to1#
- Move3form3#to2#
- Move1form1#to3#
- Move2form1#to2#
- Move1form3#to2#
- Move5form1#to3#
- Move1form2#to1#
- Move2form2#to3#
- Move1form1#to3#
- Move3form2#to1#
- Move1form3#to2#
- Move2form3#to1#
- Move1form2#to1#
- Move4form2#to3#
- Move1form1#to3#
- Move2form1#to2#
- Move1form3#to2#
- Move3form1#to3#
- Move1form2#to1#
- Move2form2#to3#
- Move1form1#to3#
在前文《递归问题一》中简单介绍了几个典型的递归问题。前几天看到一个人在论坛里问,如何实现一个字符串数组的全排列问题,底下人都说可以用递归方法实现,我想了会,没想出来,不过有人贴出了他的代码,我这里借用一下:
- publicclassAllSort{
- publicstaticvoidmain(String[]args){
- charbuf[]={'a','b','c'};
- perm(buf,0,buf.length-1);
- }
- publicstaticvoidperm(char[]buf,intstart,intend){
- if(start==end){//当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可
- for(inti=0;i<=end;i++){
- System.out.print(buf[i]);
- }
- System.out.println();
- }
- else{//多个字母全排列
- for(inti=start;i<=end;i++){
- chartemp=buf[start];//交换数组第一个元素与后续的元素
- buf[start]=buf[i];
- buf[i]=temp;
- perm(buf,start+1,end);//后续元素递归全排列
- temp=buf[start];//将交换后的数组还原
- buf[start]=buf[i];
- buf[i]=temp;
- }
- }
- }
- }
输出:
- abc
- acb
- bac
- bca
- cba
- cab
还有一个比较著名的递归问题,就是n皇后问题。就是在一个n*n的国际象棋的方格中,怎么样才能将n个皇后摆在棋盘上共存。我们知道皇后是能横着,竖着和对角线这样三条路子。以8皇后为例讨论这个问题,那么为了和Java中的数组第一个索引0更好的结合起来,我们定义8*8的棋盘中每个方格的坐标为(0, 0),(0, 1)...假定两个皇后(i, j),(k, l),那么这两个皇后的坐标一定得满足:(i != k) && (j != l) &&(|i-k| != |j-l|)。我们以一个长度为8的数组表示皇后的坐标,例如(0, 1, 2, ... , 7),这就意味着第一个皇后摆在(0, 0)上,第二个皇后在(1, 1)上,依次类推。这样就能保证每个皇后的纵坐标是不一样的。下面是具体的实现代码:
- classNQueen{
- privateintnoOfSolutions;
- privateintnoOfQueens;
- privateint[]queensInRow;
- publicNQueen(){
- this.noOfQueens=8;
- this.queensInRow=newint[8];
- this.noOfSolutions=0;
- }
- publicNQueen(intqueens){
- this.noOfQueens=queens;
- this.queensInRow=newint[noOfQueens];
- this.noOfSolutions=0;
- }
- publicbooleancanPlaceQueen(intk,inti){
- for(intj=0;j<k;j++){
- if((queensInRow[j]==i)||(Math.abs(queensInRow[j]-i)==Math.abs(j-k))){
- returnfalse;
- }
- }
- returntrue;
- }
- publicvoidqueensConfiguration(intk){
- for(inti=0;i<noOfQueens;i++){
- if(canPlaceQueen(k,i)){
- queensInRow[k]=i;
- if(k==noOfQueens-1){
- printConfiguration();
- }
- else{
- queensConfiguration(k+1);
- }
- }
- }
- }
- publicvoidprintConfiguration(){
- noOfSolutions++;
- System.out.print("(");
- for(inti=0;i<noOfQueens-1;i++){
- System.out.print(queensInRow[i]+",");
- }
- System.out.println(queensInRow[noOfQueens-1]+")");
- }
- publicintsolutionsCount(){
- returnnoOfSolutions;
- }
- }
- publicclassTestNQueen{
- publicstaticvoidmain(Stringargs[]){
- NQueenqueen=newNQueen();
- queen.queensConfiguration(0);
- }
- }
输出:
- (0,4,7,5,2,6,1,3)
- (0,5,7,2,6,3,1,4)
- (0,6,3,5,7,1,4,2)
- (0,6,4,7,1,3,5,2)
- (1,3,5,7,2,0,6,4)
- (1,4,6,0,2,7,5,3)
- (1,4,6,3,0,7,5,2)
- (1,5,0,6,3,7,2,4)
- (1,5,7,2,0,3,6,4)
- (1,6,2,5,7,4,0,3)
- (1,6,4,7,0,3,5,2)
- (1,7,5,0,2,4,6,3)
- (2,0,6,4,7,1,3,5)
- (2,4,1,7,0,6,3,5)
- (2,4,1,7,5,3,6,0)
- (2,4,6,0,3,1,7,5)
- (2,4,7,3,0,6,1,5)
- (2,5,1,4,7,0,6,3)
- (2,5,1,6,0,3,7,4)
- (2,5,1,6,4,0,7,3)
- (2,5,3,0,7,4,6,1)
- (2,5,3,1,7,4,6,0)
- (2,5,7,0,3,6,4,1)
- (2,5,7,0,4,6,1,3)
- (2,5,7,1,3,0,6,4)
- (2,6,1,7,4,0,3,5)
- (2,6,1,7,5,3,0,4)
- (2,7,3,6,0,5,1,4)
- (3,0,4,7,1,6,2,5)
- (3,0,4,7,5,2,6,1)
- (3,1,4,7,5,0,2,6)
- (3,1,6,2,5,7,0,4)
- (3,1,6,2,5,7,4,0)
- (3,1,6,4,0,7,5,2)
- (3,1,7,4,6,0,2,5)
- (3,1,7,5,0,2,4,6)
- (3,5,0,4,1,7,2,6)
- (3,5,7,1,6,0,2,4)
- (3,5,7,2,0,6,4,1)
- (3,6,0,7,4,1,5,2)
- (3,6,2,7,1,4,0,5)
- (3,6,4,1,5,0,2,7)
- (3,6,4,2,0,5,7,1)
- (3,7,0,2,5,1,6,4)
- (3,7,0,4,6,1,5,2)
- (3,7,4,2,0,6,1,5)
- (4,0,3,5,7,1,6,2)
- (4,0,7,3,1,6,2,5)
- (4,0,7,5,2,6,1,3)
- (4,1,3,5,7,2,0,6)
- (4,1,3,6,2,7,5,0)
- (4,1,5,0,6,3,7,2)
- (4,1,7,0,3,6,2,5)
- (4,2,0,5,7,1,3,6)
- (4,2,0,6,1,7,5,3)
- (4,2,7,3,6,0,5,1)
- (4,6,0,2,7,5,3,1)
- (4,6,0,3,1,7,5,2)
- (4,6,1,3,7,0,2,5)
- (4,6,1,5,2,0,3,7)
- (4,6,1,5,2,0,7,3)
- (4,6,3,0,2,7,5,1)
- (4,7,3,0,2,5,1,6)
- (4,7,3,0,6,1,5,2)
- (5,0,4,1,7,2,6,3)
- (5,1,6,0,2,4,7,3)
- (5,1,6,0,3,7,4,2)
- (5,2,0,6,4,7,1,3)
- (5,2,0,7,3,1,6,4)
- (5,2,0,7,4,1,3,6)
- (5,2,4,6,0,3,1,7)
- (5,2,4,7,0,3,1,6)
- (5,2,6,1,3,7,0,4)
- (5,2,6,1,7,4,0,3)
- (5,2,6,3,0,7,1,4)
- (5,3,0,4,7,1,6,2)
- (5,3,1,7,4,6,0,2)
- (5,3,6,0,2,4,1,7)
- (5,3,6,0,7,1,4,2)
- (5,7,1,3,0,6,4,2)
- (6,0,2,7,5,3,1,4)
- (6,1,3,0,7,4,2,5)
- (6,1,5,2,0,3,7,4)
- (6,2,0,5,7,4,1,3)
- (6,2,7,1,4,0,5,3)
- (6,3,1,4,7,0,2,5)
- (6,3,1,7,5,0,2,4)
- (6,4,2,0,5,7,1,3)
- (7,1,3,0,6,4,2,5)
- (7,1,4,2,0,6,3,5)
- (7,2,0,5,1,4,6,3)
- (7,3,0,2,5,1,6,4)
好了,希望这两篇blog能帮助你了解递归的思维方式,欢迎拍砖!