我需要创建32位数字(有符号或无符号都无所谓,无论如何都不会设置最高位),并且每个数字都必须设置给定的位数。
最简单的解决方案当然是从零开始。现在,在循环中将数字加一,对位数进行计数,如果计数具有所需的值,则将数字存储到列表中,否则循环将重复一次。如果找到足够的数字,则循环将停止。当然,这工作得很好,但是一旦所需位数变得很高,它就会非常慢。
(假设)设置5位最简单的数字是设置前5位的数字。这个数字可以很容易地创建。在循环内,第一位被设置,数字向左移动一个。该循环运行了5次,我发现第一个设置了5位的数字。接下来的两个数字也很容易创建。现在,我们假装该数字为6位宽,并且最高位未设置。现在我们开始将第一个零位向右移动,因此我们得到101111、110111、111011、111101、111110。我们可以通过在前面添加另一个0并重复此过程来重复此操作。0111110、1011110、1101110等。但是,这种方式会比所需的增长速度快得多,因为使用这种简单的方法,我们忽略了1010111之类的数字。
那么,有没有一种更好的方法可以创建所有可能的排列,这是一种通用方法,无论下一个数字将有多少位,又不管我们需要设置多少个设置位,都可以使用?
您可以使用来自hackersdelight.org的可疑黑客工具。
在他的书中,他具有用相同的一位数集获得下一个更高数字的代码。
如果您将其用作增加数量的原始方法,那么您要做的就是找到一个起点。通过设置N位获得第一个数字很容易。只是2 ^(N-1)-1。
您将以这种方式快速遍历所有可能的数字。
unsigned next_set_of_n_elements(unsigned x) { unsigned smallest, ripple, new_smallest, ones; if (x == 0) return 0; smallest = (x & -x); ripple = x + smallest; new_smallest = (ripple & -ripple); ones = ((new_smallest/smallest) >> 1) - 1; return ripple | ones; } // test code (shown for two-bit digits) void test (void) { int bits = 2; int a = pow(2,bits) - 1; int i; for (i=0; i<100; i++) { printf ("next number is %d\n", a); a = next_set_of_n_elements(a); } }