2011-06-20 40 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(" "); 
    }