【问题标题】:Using binary counting to count all subsets of an array使用二进制计数来计算数组的所有子集
【发布时间】:2014-08-26 08:15:17
【问题描述】:

所以如果给我一个数组,比如

a = {1, 2, 3} 

我们知道给定的子数组(包括不连续的)是(这代表幂集)

{1} {2} {3} {1,2,3} {1,2} {1,3} {2,3}

我也知道这些子集可以用二进制计数来表示

000 -> 111 (0 to 7), where each 1 bit means we 'use' this value from the array
e.g. 001 corresponds to the subset {3}

我知道这种方法可以以某种方式用于生成所有子集,但我不确定如何在 c++ 中实现它

所以基本上我要问的是如何(如果可以的话)二进制计数来生成幂集?

也非常感谢任何其他生成幂集的方法!

【问题讨论】:

    标签: c++ binary counting powerset


    【解决方案1】:

    对于具有 3 个集合元素的示例,您可以这样做:

    for (s = 1; s <= 7; ++s)
    {
         // ...
    }
    

    这是一个演示程序:

    #include <iostream>
    
    int main()
    {
        const int num_elems = 3;                      // number of set elements
        const int elems[num_elems] = { 1, 2, 3 };     // mapping of set element positions to values
    
        for (int s = 1; s < (1 << num_elems); ++s)    // iterate through all non-null sets
        {
            // print the set
            std::cout << "{";
            for (int e = 0; e < num_elems; ++e)       // for each set element
            {
                if (s & (1 << e))                     // test for membership of set
                {
                    std::cout << " " << elems[e];
                }
            }
            std::cout << " }" << std::endl;
        }
        return 0;
    }
    

    编译测试:

    $ g++ -Wall sets.cpp && ./a.out
    
    { 1 }
    { 2 }
    { 1 2 }
    { 3 }
    { 1 3 }
    { 2 3 }
    { 1 2 3 }
    

    请注意,使最低有效位对应于第一个集合元素是一种常见的约定。

    另请注意,我们省略了空集 s = 0,因为您似乎不想包含它。

    如果您需要处理大于 64 个元素的集合(即 uint64_t),那么您需要一种更好的方法 - 您可以扩展上述方法以使用多个整数元素,或使用 std::bitset 或 @987654326 @,或使用类似@Yochai 的答案(使用std::next_permutation)。

    【讨论】:

    • 我知道这是我问题的“什么”部分,我知道给定集合大小 3,幂集中有 7 个元素,它们对应于二进制表示。我不知道如何进行实际的二进制计数(这是您现在已删除的答案 WhozCraig 中的内容)
    • “二进制计数”是什么意思?上面的 for 循环遍历所有集合,如果这就是您的意思?
    • 是的,for 循环从 1 计数到 7,它实际上并没有做任何事情。我已经知道要创建多少个集合,但是我不知道如何实际创建它们
    • 没问题 - 我猜你没有看到位和集合成员之间的联系 - 我现在添加了一些代码来演示如何显示每个集合。
    • 非常感谢,我看到了连接,只是在使用位操作时我是一个完全的新手(现在才刚刚开始学习),显然有一些误解!
    【解决方案2】:

    实际上创建集合非常简单 - 只需使用按位运算 &gt;&gt;=&amp; 一次测试一点。假设输入向量/数组a[] 已知有 3 个元素,因此产生 7 个向量输出:

    std::vector<std::vector<T>> v(7);
    for (int n = 1; n <= 7; ++n)   // each output set...
        for (int i = 0, j = n; j; j >>= 1, ++i)  // i moves through a[i],
                                                 // j helps extract bits in n 
            if (j & 1)
                 v[n-1].push_back(a[i]);
    

    【讨论】:

      【解决方案3】:

      对于编译时间大小,您可以使用bitset,类似:

      template <std::size_t N>
      bool increase(std::bitset<N>& bs)
      {
          for (std::size_t i = 0; i != bs.size(); ++i) {
              if (bs.flip(i).test(i) == true) {
                  return true;
              }
          }
          return false; // overflow
      }
      
      template <typename T, std::size_t N>
      void display(const std::array<T, N>& a, const std::bitset<N>& bs)
      {
          std::cout << '{';
          const char* sep = "";
      
          for (std::size_t i = 0; i != bs.size(); ++i) {
              if (bs.test(i)) {
                  std::cout << sep << a[i];
                  sep = ", ";
              }
          }
          std::cout << '}' << std::endl;
      }
      
      template <typename T, std::size_t N>
      void display_all_subsets(const std::array<T, N>& a)
      {
          std::bitset<N> bs;
      
          do {
              display(a, bs);
          } while (increase(bs));
      }
      

      Live example

      【讨论】:

        猜你喜欢
        • 2011-06-06
        • 1970-01-01
        • 2018-11-02
        • 1970-01-01
        • 1970-01-01
        • 2020-08-25
        • 1970-01-01
        • 1970-01-01
        • 2013-09-04
        相关资源
        最近更新 更多