2011-06-20 41 views
4
#include <iostream> 
using namespace std; 

int main() 
{ 
    int range = 20; 
    int totalCombinations = 0; 

    for(int i=1; i<=range-2; i++) 
    { 
     if(range>i) 
     { 
      for(int j=1; j<=range-1; j++) 
       if(j>i) 
       { 
        for(int k=1; k<=range-1; k++) 
         if(k>j) 
         { 
          for(int l=1; l<=range-1; l++) 
           if(l>k) 
           { 
            for(int m=1; m<=range-1; m++) 
             if(m>l) 
             { 
              for(int f=1; f<=range; f++) 
               if(f>m) 
               { 
                cout << " " <<i<< " " <<j<< " " <<k<< " " <<l<< " " <<m<< " " <<f; 
                cin.get(); //pause 
                totalCombinations++; 
               } 
             } 
           } 
         } 
       } 
     } 
    } 
    cout << "TotalCombinations:" << totalCombinations; 
} 
+0

意外标记为C.对不起! – GENRO

回答

4

你可以做的第一件事是using continue

for(int i=1; i<=range-2; i++) { 
{ 
    if(range<=i) { 
     continue; 
    } 

    for(int j=1; j<=range-1; j++) { 
     if(j<=i) { 
      continue; 
     } 
     //etc for all inner loops 
    } 
} 

这将大大减少嵌套和国际海事组织提高可读性。

+0

你可以这样做。或者你可以消除完全冗余的IF测试(正如我所说的......)。 +1,因为这可以更普遍地解决问题,但我认为针对这种特定情况存在更好的解决方案。 –

+0

代码不可读,不可维护。第一个是比利·奥尼尔所说的:消除不必要的“如果”。 (对于它的价值,第一个如果总是假的。) –

+0

@James Kanze:我同意这些检查是不必要的,但我建议的重构可以正式完成,并且可以更容易地注意到这些检查是不必要的。 – sharptooth

4
if(range>i) 

为什么不刚开始irange,避免这个问题?哦,我已经倒过来了,但问题依然存在 - 您可以轻松地将此重构为for条件的一部分。不需要额外的条件。

if(j>i) 

为什么不开始ji

...(重复其他两个环路)

这摆脱了一半的嵌套。就循环本身而言,我会建议对它们使用提取方法。

+0

+1:此外,'i'将始终小于'range'。 –

0

与重构任何东西的方式相同。你首先要弄清楚代码在做什么 。在这种情况下,许多测试都是不相关的,并且每个循环基本上都是相同的。你已经解决了一个非常普遍的问题的特定情况(很滑稽)。计算出 问题的一般算法将产生更简洁,更简洁的解决方案,而且更通用。事情是这样的:

class Combin 
{ 
    int m; 
    int n; 
    int total; 
    std::vector<int> values; 

    void calc(); 
    void dumpVector() const; 
public: 
    Combin(int m, int n) : m(m), n(n), total(0) {} 
    int operator()() { total = 0; values.clear(); calc(); return total; } 
}; 

void 
Combin::calc() 
{ 
    if (values.size() == m) { 
     dumpVector(); 
     ++ total; 
    } else { 
     values.push_back(values.empty() ? 0 : values.back() + 1); 
     int limit = n - (m - values.size()); 
     while (values.back() < limit) { 
      calc(); 
      ++ values.back(); 
     } 
     values.pop_back(); 
    } 
} 

void 
Combin::dumpVector() const 
{ 
    for (std::vector<int>::const_iterator iter = values.begin(); iter != values.end(); ++ iter) 
     std::cout << ' ' << *iter + 1; 
    std::cout << '\n'; 
} 

int main() 
{ 
    Combin c(6, 20); 
    std::cout << "TotalCombinations:" << c() << std::endl; 
    return 0; 
} 

唯一真不愧是在上述评论是在calclimit计算 ,那真的只是一个优化;你可以 使用n并得到相同的结果(但你会递减一些)。

你会注意到,在原始版本中, 循环的结束条件都或多或少的武断使用range系统将 工作,或者你可以工作了,我使用limit(其中 将公式结果在每个循环中的不同的结束条件。

而且,我的代码使用半开区间这是在C和 C++ ubiquious。我认为,一旦你习惯了它们,你会发现他们更 容易推理。

0

我的C++ i生锈的,所以让我给你一个C#的例子。任何数量的嵌套循环都可以用一个代替,如下所示:

public void ManyNestedLoopsTest() 
    { 
     var limits = new[] {2, 3, 4}; 
     var permutation = new[] {1, 1, 0}; 
     const int lastDigit = 2; 
     var digitToChange = lastDigit; 
     while(digitToChange >= 0) 
     { 
      if (permutation[digitToChange] < limits[digitToChange]) 
      { 
       permutation[digitToChange]++; 
       digitToChange = lastDigit; 
       PrintPermutation(permutation); 
       continue; 
      } 
      permutation[digitToChange--] = 1; 
     } 
    } 

    private void PrintPermutation(int[] permutation) 
    { 
     for(int i=0;i<3;i++) 
     { 
      Console.Write(permutation[i]); 
      Console.Write(" "); 
     } 
     Console.WriteLine(" "); 
    }