題目說明:
給定一組數字或符號,產生所有可能的集合(包括空集合),例如給定1 2 3,則可能的集合為:{}、{1}、{1,2}、{1,2,3}、{1,3}、{2}、{2,3}、{3}。
題目解析:
如果不考慮字典順序,則有個簡單的方法可以產生所有的集合,思考二進位數字加法,並注意1出現的位置,如果每個位置都對應一個數字,則由1所對應的數字所產生的就是一個集合,例如:
| 000 | {} |
| 001 | {3} |
| 010 | {2} |
| 011 | {2,3} |
| 100 | {1} |
| 101 | {1,3} |
| 110 | {1,2} |
| 111 | {1,2,3} |
了解這個方法之后,剩下的就是如何產生二進位數?有許多方法可以使用,您可以使用unsigned型別加上&位元運算來產生;
如果是32個以內的元素集合可以采用unsigned int來儲存,這樣直接遍歷再根據比特位顯示出元素就可以了。
比如3個元素,則對應最大值是2^3 = 8; for (int i=0; i < 8; i++) ShowResult(&i, 3); //根據bit位顯示結果
這里我假定任意個元素集合求子集合,通過數組來表示任意長位數;
程序代碼:
#include <gtest/gtest.h> using namespace std; void ShowResult(bool Bits[], int nSize) { cout << "{"; for (int i=0; i<nSize; ++i) { if (Bits[i]) { cout << i+1 << " "; } } cout << "}\n"; } bool Add(bool Bits[], int nSize) { for (int i = nSize -1; i >= 0; --i) { Bits[i] = !Bits[i]; // 如果是1變成0再進位,如果是0變成1退出。 if (Bits[i]) { return true; } } return false; } // 二進制法 int GenerateSubset(int nSize) { if (nSize==0) { cout << "{}" << endl; return 1; } int nCount = 0; bool *Bits = new bool[nSize]; memset(Bits, false, sizeof(bool)*nSize); do { ShowResult(Bits, nSize); nCount++; } while(Add(Bits, nSize)); delete[] Bits; return nCount; } TEST(Algo, tCombination) { // 0個數子集合數 =〉2^0 = 1 ASSERT_EQ(GenerateSubset(0), 1); // 3個數子集合數 =〉2^3 = 8 ASSERT_EQ(GenerateSubset(3), 8); // 5個數子集合數 =〉2^5 = 32 ASSERT_EQ(GenerateSubset(5), 32); // 10個數子集合數 =〉2^10 = 1024 ASSERT_EQ(GenerateSubset(10), 1024); }
參考引用:
根據組合數和二項式定理
子集個數:Cn0+Cn1+Cn2+...+Cnn = (1+1)^n=2^n
看書、學習、寫代碼

看書、學習、寫代碼