枚举二进制序列

时间:2016-03-24 23:57:09

标签: c++ c binary sequence counting

假设我想枚举所有4位模式,即来自0 (0000) to 15 (1111)。一种方法是"真值表"的方法:

0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111, ... 1111

这种方法相当于以十进制从0到15进行计数。

另一种方法是使用格雷码,其中一次只翻转一位:

0000, 0001, 0011, 0010, 0110, ... 1000

我如何系统地枚举最小化位总和的顺序中的所有数字?例如,类似于:

0000, 0001, 0010, 0100, 1000, 0011, 0101, 1001, 0110, 1010, 1001, 0111, 1011, 1101, 1110, 1111

表示4位示例。

最终,将它扩展到任何基础都会很好,但二元情况似乎是最直接的实现。

编辑:我可能应该明确表示该方法必须是生成性的,即我不能计算所有可能的序列,然后对它们进行排序;解决方案必须按照与指定顺序相似的顺序迭代生成序列。

3 个答案:

答案 0 :(得分:1)

这个笨拙的黑客

unsigned next_combination(unsigned x)
{
  unsigned u = x & -x;
  unsigned v = u + x;
  x = v  + (((v ^ x) / u) >> 2);
  return x;
}

将允许您轻松枚举按递增顺序包含相同数量的1位的所有unsigned位组合。 (见https://en.wikipedia.org/wiki/Combinatorial_number_system

您可以使用此算法按顺序枚举所有组合,包括一个1位,两个1位,三个1位,依此类推。例如,对于最多4位长的组合(如您的示例所示)

#define N 4u

int main()
{
  for (unsigned k = 1; k <= N; ++k)
  {
    for (unsigned subset = (1 << k) - 1; 
         subset < (1 << N); 
         subset = next_combination(subset))
      printf("%X ", subset);

    printf("\n");  
  }
}

http://coliru.stacked-crooked.com/a/0c8327c5e0611eaa

上面的维基百科链接还包含更多通用算法的描述,而不是依赖于任何比特麻烦。

答案 1 :(得分:0)

int main()
{

    int n, p, j, i = 0, sum;
    cin >> n;

    bool *wsk = new bool[n];
    int hmany = static_cast<int> (pow(2, n));
    bool **sortarr = new bool *[hmany];
    for (int i = 0; i < hmany; i++) sortarr[i] = new bool[n];


    bool *wsk1 = wsk;

    for (int i = 0; i < n; i++) *wsk++ = 0;
    wsk = wsk1;

    int z = 0;
    int c = n - 1;
    do
    {

        sum = 0;
        c = n - 1;
        for (int i = 0; i < n; i++)
        {
            if (wsk[i] == 1) sum += static_cast<int>(pow(2,c));
            c--;

        }
        z = sum;

        for (int i = 0; i < n; i++)
        {
            sortarr[z][i] = wsk[i];

        }

        z++; wsk = wsk1;
        i++; p = 0; j = i;

        while (j % 2 == 0)
        {
            j /= 2; p++;

        }

        if (p <= n) wsk[p] = ((1 - wsk[p]) != 0); 


    } while (p < n);

这就是你想要的一切。

答案 2 :(得分:0)

这将转储二进制值列表,按设置的二进制数字(总体)计数,升序排序。根据序数值对人口相等的数字进行排名。

使用每个唯一的4位整数填充int值数组。

std :: sort对数组进行排序,使用lambda来比较值。 lambda调用函数population来获取数字的设置位数。

然后,列表由函数dump_array输出,它将整数值转换为std::bitset,以便在发送到std :: cout时获得二进制表示。

#include <iostream>
#include <array>
#include <algorithm>
#include <bitset>


template <typename T>
int population(T x) {  // x<0 => oo loop
    int count = 0;
    while(x) {
        count += x & 1;
        x >>= 1;
    }
    return count;
}

template <typename A>
void dump_array(const A& a) {
    const char* delim = "";
    for(auto v : a) {
        std::bitset<4> bits(v);
        std::cout << delim << bits;
        delim = ", ";
    }
    std::cout << '\n';
}

int main() {
    std::array<int, 1<<4> vals;
    int i=0;
    for(auto& v : vals) { v = i++; }
    std::sort(vals.begin(), vals.end(), [](int a, int b) {
        const int pop_a = population(a);
        const int pop_b = population(b);
        return pop_a < pop_b || (pop_a == pop_b && a < b);
    });
    dump_array(vals);
}