子集生成演算法

2021-08-03 14:04:35 字數 3199 閱讀 9047

子集生成演算法屬於暴力法中一類非常重要的演算法.

給定乙個集合,請寫乙個演算法,得到其所有的子集.這裡假定該集合不存在重複的元素.

舉個栗子,給定集合[1, 2, 3], 你返回這樣一堆子集:

, [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]
根據離散數學的知識,我們可以知道,乙個長度為n的集合的子集有2n個,集合的元素其實可以對應到乙個長度為n個二進位制數上.該二進位制數的第i位如果為1,表示取集合的第i個元素,否則表示不取.

舉個例子[1, 2, 3]可以對應到乙個長度為3的二進位制數上.111表示[1, 2, 3],011表示[2, 3].

二進位制數000...00~111...11,每個數都對應了乙個子集,首先這些數各不相同,其次這些數的總數為2n,所以這些數對應的子集正好對應了該集合的全部子集.

下面是這種方法的乙個簡易實現:

#include 

#include

#include

using

namespace

std;

/** * 位向量法.

* 假定set的元素個數為n,那麼用乙個長度為n的bool陣列來模擬位向量,陣列的第i個元素為true,表示選擇set

* 的第i個元素, 否則表示不選擇.假定我們從二進位制的 000....00 (n個0) 開始數數, 一直數到 111...11

* (n個1)的話, 我們會發現我們數的每乙個數,都對應了set的乙個子集.利用這點,可以很快地寫出子集尋找演算法.

* 舉個例子,假定set為[1, 2, 3], 位向量001表示選擇第3個元素,即[3]是set的乙個子集.

* 位向量111表示[1, 2, 3]為set的乙個子集.

*//**

* @brief 尋找所有的子集

* @param[in] set 集合

* @param[in] mask 位標記

* @param[in] pos 當前已經處理到了第pos個位置了.

* @param[in, out] subsets 用於記錄結果的陣列.

*/void findsubsets(vector

& set, bool mask, int pos, vector

>& subsets)

subsets.push_back(subset);

return;

}mask[pos] = true;

findsubsets(set, mask, pos + 1, subsets);

mask[pos] = false;

findsubsets(set, mask, pos + 1, subsets);

}/**

* @brief 尋找set的所有子集.

* @param[in] set 包含了所有元素的集合

* @return 所有子集構成的陣列

*/vector

> subsets(vector

& set)

int main()

; auto subsets = subsets(nums);

for (auto &subset : subsets)

cout

<< endl;

}getchar();

}

這種方法比上面的位向量法稍微難以理解一點,不過做法也相當有意思.

很簡單,自然是遍歷集合的後n - k個元素,將每乙個元素新增到該子集後面即可.

很簡單,對於集合的第k + 1個元素,我們可以選擇新增進有前k個元素構成的子集,這樣可以生成2k個子集. 也可以選擇不新增,可以生成2k個子集,恰好是前k個元素構成的子集.

增量構造法結合了這兩點.

這種方法的簡單實現如下:

#include 

#include

#include

using

namespace

std;

/** * 增量構造法

* 這種方法比位向量法稍微要複雜一些.事實上,我並不推薦這種方法,它並沒有比位向量法效率更高或者

* 更容易理解.

*//**

* @brief 尋找所有長度為subsetidx + 1的子集

* @param[in] set 要求子集的集合

* @param[in] setidx 用於表示集合的下標從0~setidx-1的元素即前setidx個元素在這輪迭代中不能再取.

* @param[in] subset 由集合的前setidx元素組合而成的長度為subsetidx的子集.

* @param[in] subsetidx 子集的長度.

* @param[in/out] subsets 用於記錄所有的子集的陣列

* @return 無

*/void findsubsets(vector

& set, int setidx, int* subset, int subsetidx, vector

>& subsets)

}/**

* @brief 尋找set的所有子集.

* @param[in] set 包含了所有元素的集合

* @return 所有子集構成的陣列

*/vector

> subsets(vector

& set)

int main()

; auto subsets = subsets(nums);

for (auto &subset : subsets)

cout

<< endl;

}getchar();

}

子集生成演算法

劉汝佳書上的內容 下文提到的集合 其元素預設為0 n 1 n 個 意思就是一次選乙個 放到 裡 include include include include include include include include include include include include includ...

子集生成演算法

1.增量構造法 基本思路 一次選出乙個元素放到集合中。使用前序遍歷的方法,因為a中元素個數不確定,每次遞迴呼叫都要輸出當前集合。演算法流程 另外,為了避免出現類似於按照和輸出兩次,可以使用定序的技巧,即規定集合a中所有元素的編號從小到大排列,對應於程式中的int s cur?a cur 1 1 0 ...

子集生成演算法

給定乙個集合 沒有重複元素 輸出所有子集。首先考慮1 n的所有子集 為了不出現和的情況,採用定序的方法。想象一棵解答樹,子節點的元素一定比父節點大。因為定序,解答樹葉子結點的深度不同。解答樹上的每乙個結點有個值,從根節點到葉子結點路徑上的結點值為乙個集合,每加乙個結點就輸出一次。如下 輸入n inc...