適合小白的暴力求子集方法, 瞭解一下?
阿新 • • 發佈:2019-02-19
前言
最近在上C++課的時候老師留了一道課後作業,求n個數字的全部子集,比如說輸入6就列印{1, 2, 3, 4,5, 6}的全部子集。
當時我腦中第一反應就是用遞迴列舉隨便打一打啊,不過後來有位同學問我思路,突然不知所措,因為我們當時才講了基本資料型別和while、if、for這幾種控制選擇結構,陣列函式神馬的都還沒有講,那麼,用這些最基本的知識要怎麼做呢?
雖然道理上講是所有的演算法問題都能用控制結構的堆疊巢狀來解決,不過落實到程式碼上真的有點無力。
我也嘗試去網上找答案,不過不管換了多少關鍵字搜尋,基本上都是那麼幾種求法,增量構造啦、二進位制啦、位向量啦。。。看著一個比一個高階,可搜了好久也沒有找到最最最最最原始的方法,後來我想了一段時間並汲取了網上的一些思想,寫了一個簡單的暴力列舉演算法 。
思路
n個元素的集合的子集數就是2的n次冪嘛(貌似是初中講的,不清楚的翻筆記去啦),所以外層迴圈就是迴圈2的n次冪次。
for (int i=0; i<pow(2, n); i++)
{
}
內部實現的話就是先用temp儲存一下i的值,然後用for迴圈確定集合中的每個元素是否應該被打印出來,那麼如何確定呢?即判斷temp的奇偶,而且每次內部for迴圈都改變temp的值。
temp=i; for(j=0; j<n; j++) { if (temp%2 != 0) { cout<<j+1; } temp=temp/2; } cout<<" }"<<endl;
完整程式碼
可以加一些花括號逗號之類的易於區分自己中的每個元素(不過我的程式碼好像有點問題,晚上再改吧,畢竟基電作業還沒寫QAQ)
#include <iostream> #include <cmath> using namespace std; int main() { int i, j, n, temp; cin>>n; for(i=0; i<pow(2,n); i++) { temp=i; cout<<"{ "; for(j=0; j<n; j++) { if (temp%2 != 0) { cout<<j+1; if (j != n-1) cout<<", "; } temp=temp/2; } cout<<" }"<<endl; } return 0; }
新的程式碼可以判斷輸入的元素是否有重複,如果重複的話就把多餘的元素刪除後再求其子集;同時,新的方法可以輸入任意型別的字串(本來就是用字串來接收的啊)。
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
int i,j;
int n;
int temp, count;
string s1;
cout<<"請輸入集合中元素的個數"<<endl;
cin>>n;
// 判斷輸入的元素是否重複
string *input = new string[n];
for (int t=0; t<n; t++)
{
cin>>s1;
count = 0;
for (int k=0; k<t; k++)
if (input[k] == s1)
{
count++;
n--;
t--;
}
if (0 == count)
input[t] = s1;
}
//動態建立陣列
string *s = new string[n];
for (int i=0; i<n; i++)
s[i] = input[i];
for(i=0; i<pow(2,n); i++)
{
//外層迴圈迴圈2的n次冪次
temp=i;
cout<<"{ ";
for(j=0; j<n; j++)
{
if (temp%2 != 0)
{
cout<<s[j];
if (j != n-1)
cout<<" ";
}
temp = temp / 2;
}
cout<<" }"<<endl;
}
//清除陣列的記憶體空間
delete[] s;
delete[] input;
}
後記
這次思考還是比較有意義的,以後學習演算法的時候儘量先去用最原始的方式實現,然後計算時間複雜度、空間複雜度,再去用所謂高階一些的技巧優化,更為完善的程式碼晚上再整理貼出來吧。