递归的使用——关于括号排列(分别使用Java和C++算法实现)

    接到一个同学的询问,说是在做一个括号匹配的输出,大意是这样的:

       定义一个整数n 表示括号对数,然后枚举出所有的合理括号组合形式。如当n = 1,只有“()”这样一种情形;当n = 2时,有“()()”和“(())”两种情况。依次列举。   

    由于我使用Java还不大习惯,我使用的是C++实现。而我的同学则使用Java的实现。现将两种算法共享如下:

    ㈠:Java的算法:

       个人评价:算法简洁,不过由于不是自己写的,现在仍感觉有点难看懂。

  1. public class Kuohao 
  2. {
  3.     int n;
  4.     String All="";//若此处改为String All = null;则会输出结果前端都会有“null”字符。
  5.     public Kuohao(int n)
  6.     {
  7.         this.n=n;
  8.     }
  9.     public void PrintAll(String All,int left,int right)
  10.     {
  11.         if(right==0)
  12.         {
  13.             System.out.println(All);
  14.             return;
  15.         }
  16.         else if(left==right)
  17.         {
  18.             All+="(";
  19.             PrintAll(All,--left,right);
  20.         }
  21.         else if(left<right && left>0)
  22.         {
  23.             String a=All;
  24.             All+="(";
  25.             PrintAll(All,--left,right);
  26.             left++;
  27.             a+=")";
  28.             PrintAll(a,left,--right);
  29.         }
  30.         else if(left==0)
  31.         {
  32.             All+=")";
  33.             PrintAll(All,left,--right);
  34.         }
  35.     }
  36.     public static void  main(String []args)
  37.     {
  38.         Kuohao kuohao=new Kuohao(3);
  39.         kuohao.PrintAll(kuohao.All,kuohao.n,kuohao.n);
  40.     }
  41. }

输出结果:

  1. ((()))
  2. (()())
  3. (())()
  4. ()(())
  5. ()()()

      ㈡:自己写的C++算法:

    个人评价:应该是简单易懂的,但是代码长度比起Java来显然长了许多。

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. void main(){
  5.     void PaintAll(string All,int left,int right);
  6.     string All = "";
  7.     int n = 3;
  8.     PaintAll(All,n,n);
  9. }
  10. void PaintAll(string All,int left,int right){
  11.     string LeftAll = All,RightAll = All;//由此以下三句为保护All与left,right.
  12.     int LeftLeft = left,LeftRight = right;//缘由是因为用了for循环,在循环中的两种情况下,使用的都
  13. //必须是同一个数据源,不可以被更改
  14.     int RightLeft = left,RightRight = right;
  15.     if(left == 0){
  16.         while(right != 0){
  17.             All += ")";
  18.             right --;
  19.         }
  20.         cout << All << endl;
  21.         return ;
  22.     }
  23.     for(int i = 0;i < 2; i ++){
  24.         switch(i){
  25.         case 0:
  26.             LeftLeft --;
  27.             if(LeftLeft < 0){
  28.                 LeftLeft = 0;
  29.                 continue;
  30.             }else{
  31.                 LeftAll += "("
  32.                 PaintAll(LeftAll,LeftLeft,LeftRight);
  33.             }
  34.         break;
  35.         default:
  36.             if(RightLeft < RightRight){
  37.                 RightRight --;
  38.                 if(RightRight < 0){
  39.                     RightRight = 0;
  40.                     break;
  41.                 }else{
  42.                     RightAll += ")";
  43.                     PaintAll(RightAll,RightLeft,RightRight);
  44.                 }
  45.             }
  46.         break;
  47.         }
  48.     }
  49. }

 

输出结果:

 

 

 

若没有Line 13,14,16的保护,则输出的错误结果

 

  1. ((()))
  2. ((()))
  3. (()())
  4. (()())
  5. ()(())
  6. ()(())
  7. ()()()
  8. ()()()

很奇怪的结果吧,这是因为当for循环中i = 1;时所使用的All,left,right都已经是在i = 0时所加工过的了,不是原始数据了。

佐证:

看第4,5,6,7行,这就是问题所在。

 

 

C++算法的优化:

可以看到,for循环里,变量i只是从0变化到1,switch语句也只是进行0,与1的选择,所以可以省去for与switch语句。又有进行递归时,传进递归函数的必须是初始的原始数据,所以不必设定两组暂时的存储变量{LeftAll,LeftLeft,LeftRight},{RightAll,RightLeft,RightRight},而可以改为一组{tempAll,tempLeft,tempRight},在每个递归函数前,重新对tempLeft和tempRight赋值为:

tempAll = All;

tempLeft = Left;

tempRight = Right;

 

改进的算法如下,可以看见代码的长度也缩减为44行了,如果去除包含3句头语句,则比Java算法代码还少一句,所以可见优化的作用:

 

 

 
  1. #include <iostream> 
  2. #include <string> 
  3. using namespace std; 
  4. void main(){ 
  5.     void PaintAll(string All,int left,int right); 
  6.     string All = ""
  7.     int n = 3; 
  8.     PaintAll(All,n,n); 
  9. void PaintAll(string All,int left,int right){ 
  10.     if(left == 0){ 
  11.         while(right != 0){ 
  12.             All += ")"
  13.             right --; 
  14.         } 
  15.         cout << All << endl; 
  16.         return ; 
  17.     } 
  18.     string tempAll = All;
  19.     int tempLeft = left,tempRight = right;
  20.     tempLeft --; 
  21.     if(tempLeft < 0){ 
  22.         tempLeft = 0; 
  23.     }else
  24.         tempAll += "(";  
  25.         PaintAll(tempAll,tempLeft,tempRight); 
  26.     }
  27.     tempAll = All;
  28.     tempLeft = left;
  29.     tempRight = right;
  30.     if(tempLeft < tempRight){ 
  31.         tempRight --; 
  32.         if(tempRight < 0){ 
  33.             tempRight = 0; 
  34.         }else
  35.             tempAll += ")"
  36.             PaintAll(tempAll,tempLeft,tempRight); 
  37.         } //else if
  38.     } //if
  39. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值