c++ - 枚举二进制序列

标签 c++ c binary sequence counting

假设我想枚举所有 4 位模式,即从 0 (0000) 到 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 位示例。

最终,将其扩展到任何基础都会很好,但二进制情况似乎是最容易实现的。

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

最佳答案

这个有点麻烦的黑客

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

将允许您轻松枚举包含相同数量的 1 位(按升序排列)的所有无符号位组合。 (参见https://en.wikipedia.org/wiki/Combinatorial_number_system)

您可以使用此算法依次枚举所有具有 1 个 1 位、2 个 1 位、3 个 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

上面的维基百科链接还包含更通用算法的描述,不依赖于任何位操作。

关于c++ - 枚举二进制序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36211988/

相关文章:

c - 如何将大十进制值转换为二进制

c++ - 使用 gcc/g++ 编译器编译 c++

c - 将函数指针转换为 void 有什么影响?

c - 函数中未声明的变量

c - 仅当从 busybox 上的 inittab 启动时应用程序才会崩溃

http - 为什么HTTP协议(protocol)要设计成明文方式?

ios - 否 在新的 iTunes Connect 10/09 中拒绝此二进制链接

c++ - Eclipse:注释整个代码而不会被其他注释打断

c++ - Qt:keyPressEvent 中的打印屏幕键

c++ - 手动生成 mipmap