递归问题

转自:http://blog.youkuaiyun.com/justinavril/archive/2008/08/01/2753596.aspx

所谓递归问题,可以分成两部分来理解:一是基本问题,也可以称之为原始问题,比较好解决;二是后续问题,比较复杂,但是和原始问题比较类似,可以调用自身的一个新的副本去解决它。

最简单的可以归为递归问题的就是阶乘,1的阶乘我们知道是1,2的阶乘为2*1=2*1!,而3的阶乘又是3*2!...这样我们就能够知道如何用递归去实现n的阶乘了。

  1. publicclassFactorial{
  2. publicstaticintfactorial(intn){
  3. intresult=0;
  4. if(n<=1){
  5. result=1;
  6. }
  7. elseif(n>1){
  8. result=n*factorial(n-1);
  9. }
  10. returnresult;
  11. }
  12. publicstaticvoidmain(Stringargs[]){
  13. for(inti=0;i<10;i++)
  14. System.out.print(factorial(i)+"");
  15. }
  16. }

输出:

  1. 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号柱子为临时存放点。

请看代码:

  1. publicclassHanoi{
  2. publicstaticvoidhanoi(intmovingPans,StringsourcePillar,StringtargetPillar,StringtempPillar){
  3. if(movingPans==1){
  4. movePans(1,sourcePillar,targetPillar);
  5. }
  6. else{
  7. hanoi(movingPans-1,sourcePillar,tempPillar,targetPillar);
  8. movePans(movingPans,sourcePillar,targetPillar);
  9. hanoi(movingPans-1,tempPillar,targetPillar,sourcePillar);
  10. }
  11. }
  12. publicstaticvoidmovePans(intpanNum,StringsourcePillar,StringtargetPillar){
  13. System.out.println("Move"+panNum+"form"+sourcePillar+"#to"+targetPillar+"#");
  14. }
  15. publicstaticvoidmain(Stringargs[]){
  16. System.out.println("3个盘子的汉诺塔问题:");
  17. hanoi(3,"1","3","2");
  18. System.out.println("5个盘子的汉诺塔问题:");
  19. hanoi(5,"1","3","2");
  20. }
  21. }

输出:

  1. 3个盘子的汉诺塔问题:
  2. Move1form1#to3#
  3. Move2form1#to2#
  4. Move1form3#to2#
  5. Move3form1#to3#
  6. Move1form2#to1#
  7. Move2form2#to3#
  8. Move1form1#to3#
  9. 5个盘子的汉诺塔问题:
  10. Move1form1#to3#
  11. Move2form1#to2#
  12. Move1form3#to2#
  13. Move3form1#to3#
  14. Move1form2#to1#
  15. Move2form2#to3#
  16. Move1form1#to3#
  17. Move4form1#to2#
  18. Move1form3#to2#
  19. Move2form3#to1#
  20. Move1form2#to1#
  21. Move3form3#to2#
  22. Move1form1#to3#
  23. Move2form1#to2#
  24. Move1form3#to2#
  25. Move5form1#to3#
  26. Move1form2#to1#
  27. Move2form2#to3#
  28. Move1form1#to3#
  29. Move3form2#to1#
  30. Move1form3#to2#
  31. Move2form3#to1#
  32. Move1form2#to1#
  33. Move4form2#to3#
  34. Move1form1#to3#
  35. Move2form1#to2#
  36. Move1form3#to2#
  37. Move3form1#to3#
  38. Move1form2#to1#
  39. Move2form2#to3#
  40. Move1form1#to3#

在前文《递归问题一》中简单介绍了几个典型的递归问题。前几天看到一个人在论坛里问,如何实现一个字符串数组的全排列问题,底下人都说可以用递归方法实现,我想了会,没想出来,不过有人贴出了他的代码,我这里借用一下:

  1. publicclassAllSort{
  2. publicstaticvoidmain(String[]args){
  3. charbuf[]={'a','b','c'};
  4. perm(buf,0,buf.length-1);
  5. }
  6. publicstaticvoidperm(char[]buf,intstart,intend){
  7. if(start==end){//当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可
  8. for(inti=0;i<=end;i++){
  9. System.out.print(buf[i]);
  10. }
  11. System.out.println();
  12. }
  13. else{//多个字母全排列
  14. for(inti=start;i<=end;i++){
  15. chartemp=buf[start];//交换数组第一个元素与后续的元素
  16. buf[start]=buf[i];
  17. buf[i]=temp;
  18. perm(buf,start+1,end);//后续元素递归全排列
  19. temp=buf[start];//将交换后的数组还原
  20. buf[start]=buf[i];
  21. buf[i]=temp;
  22. }
  23. }
  24. }
  25. }

输出:

  1. abc
  2. acb
  3. bac
  4. bca
  5. cba
  6. 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)上,依次类推。这样就能保证每个皇后的纵坐标是不一样的。下面是具体的实现代码:

  1. classNQueen{
  2. privateintnoOfSolutions;
  3. privateintnoOfQueens;
  4. privateint[]queensInRow;
  5. publicNQueen(){
  6. this.noOfQueens=8;
  7. this.queensInRow=newint[8];
  8. this.noOfSolutions=0;
  9. }
  10. publicNQueen(intqueens){
  11. this.noOfQueens=queens;
  12. this.queensInRow=newint[noOfQueens];
  13. this.noOfSolutions=0;
  14. }
  15. publicbooleancanPlaceQueen(intk,inti){
  16. for(intj=0;j<k;j++){
  17. if((queensInRow[j]==i)||(Math.abs(queensInRow[j]-i)==Math.abs(j-k))){
  18. returnfalse;
  19. }
  20. }
  21. returntrue;
  22. }
  23. publicvoidqueensConfiguration(intk){
  24. for(inti=0;i<noOfQueens;i++){
  25. if(canPlaceQueen(k,i)){
  26. queensInRow[k]=i;
  27. if(k==noOfQueens-1){
  28. printConfiguration();
  29. }
  30. else{
  31. queensConfiguration(k+1);
  32. }
  33. }
  34. }
  35. }
  36. publicvoidprintConfiguration(){
  37. noOfSolutions++;
  38. System.out.print("(");
  39. for(inti=0;i<noOfQueens-1;i++){
  40. System.out.print(queensInRow[i]+",");
  41. }
  42. System.out.println(queensInRow[noOfQueens-1]+")");
  43. }
  44. publicintsolutionsCount(){
  45. returnnoOfSolutions;
  46. }
  47. }
  48. publicclassTestNQueen{
  49. publicstaticvoidmain(Stringargs[]){
  50. NQueenqueen=newNQueen();
  51. queen.queensConfiguration(0);
  52. }
  53. }

输出:

  1. (0,4,7,5,2,6,1,3)
  2. (0,5,7,2,6,3,1,4)
  3. (0,6,3,5,7,1,4,2)
  4. (0,6,4,7,1,3,5,2)
  5. (1,3,5,7,2,0,6,4)
  6. (1,4,6,0,2,7,5,3)
  7. (1,4,6,3,0,7,5,2)
  8. (1,5,0,6,3,7,2,4)
  9. (1,5,7,2,0,3,6,4)
  10. (1,6,2,5,7,4,0,3)
  11. (1,6,4,7,0,3,5,2)
  12. (1,7,5,0,2,4,6,3)
  13. (2,0,6,4,7,1,3,5)
  14. (2,4,1,7,0,6,3,5)
  15. (2,4,1,7,5,3,6,0)
  16. (2,4,6,0,3,1,7,5)
  17. (2,4,7,3,0,6,1,5)
  18. (2,5,1,4,7,0,6,3)
  19. (2,5,1,6,0,3,7,4)
  20. (2,5,1,6,4,0,7,3)
  21. (2,5,3,0,7,4,6,1)
  22. (2,5,3,1,7,4,6,0)
  23. (2,5,7,0,3,6,4,1)
  24. (2,5,7,0,4,6,1,3)
  25. (2,5,7,1,3,0,6,4)
  26. (2,6,1,7,4,0,3,5)
  27. (2,6,1,7,5,3,0,4)
  28. (2,7,3,6,0,5,1,4)
  29. (3,0,4,7,1,6,2,5)
  30. (3,0,4,7,5,2,6,1)
  31. (3,1,4,7,5,0,2,6)
  32. (3,1,6,2,5,7,0,4)
  33. (3,1,6,2,5,7,4,0)
  34. (3,1,6,4,0,7,5,2)
  35. (3,1,7,4,6,0,2,5)
  36. (3,1,7,5,0,2,4,6)
  37. (3,5,0,4,1,7,2,6)
  38. (3,5,7,1,6,0,2,4)
  39. (3,5,7,2,0,6,4,1)
  40. (3,6,0,7,4,1,5,2)
  41. (3,6,2,7,1,4,0,5)
  42. (3,6,4,1,5,0,2,7)
  43. (3,6,4,2,0,5,7,1)
  44. (3,7,0,2,5,1,6,4)
  45. (3,7,0,4,6,1,5,2)
  46. (3,7,4,2,0,6,1,5)
  47. (4,0,3,5,7,1,6,2)
  48. (4,0,7,3,1,6,2,5)
  49. (4,0,7,5,2,6,1,3)
  50. (4,1,3,5,7,2,0,6)
  51. (4,1,3,6,2,7,5,0)
  52. (4,1,5,0,6,3,7,2)
  53. (4,1,7,0,3,6,2,5)
  54. (4,2,0,5,7,1,3,6)
  55. (4,2,0,6,1,7,5,3)
  56. (4,2,7,3,6,0,5,1)
  57. (4,6,0,2,7,5,3,1)
  58. (4,6,0,3,1,7,5,2)
  59. (4,6,1,3,7,0,2,5)
  60. (4,6,1,5,2,0,3,7)
  61. (4,6,1,5,2,0,7,3)
  62. (4,6,3,0,2,7,5,1)
  63. (4,7,3,0,2,5,1,6)
  64. (4,7,3,0,6,1,5,2)
  65. (5,0,4,1,7,2,6,3)
  66. (5,1,6,0,2,4,7,3)
  67. (5,1,6,0,3,7,4,2)
  68. (5,2,0,6,4,7,1,3)
  69. (5,2,0,7,3,1,6,4)
  70. (5,2,0,7,4,1,3,6)
  71. (5,2,4,6,0,3,1,7)
  72. (5,2,4,7,0,3,1,6)
  73. (5,2,6,1,3,7,0,4)
  74. (5,2,6,1,7,4,0,3)
  75. (5,2,6,3,0,7,1,4)
  76. (5,3,0,4,7,1,6,2)
  77. (5,3,1,7,4,6,0,2)
  78. (5,3,6,0,2,4,1,7)
  79. (5,3,6,0,7,1,4,2)
  80. (5,7,1,3,0,6,4,2)
  81. (6,0,2,7,5,3,1,4)
  82. (6,1,3,0,7,4,2,5)
  83. (6,1,5,2,0,3,7,4)
  84. (6,2,0,5,7,4,1,3)
  85. (6,2,7,1,4,0,5,3)
  86. (6,3,1,4,7,0,2,5)
  87. (6,3,1,7,5,0,2,4)
  88. (6,4,2,0,5,7,1,3)
  89. (7,1,3,0,6,4,2,5)
  90. (7,1,4,2,0,6,3,5)
  91. (7,2,0,5,1,4,6,3)
  92. (7,3,0,2,5,1,6,4)

好了,希望这两篇blog能帮助你了解递归的思维方式,欢迎拍砖!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值