让我们说combinationlength
= 4。
我的逻辑是在最后一个元素上array {0,0,0,0}
添加1
,直到第一个元素得到值1
。直到添加1
,array[3]
最终得到2
结果,然后使其成为0
,然后遍历给定counter variable
的数组(反转),并且每个第一个非1
元素都使其成为0
同时使第一个非1
之前的所有元素等于0
。这是8次重复。我离我有多近?有人可以帮我完成这个工作吗?
由于某些原因,此操作也无法运行。2秒钟后什么都不会打印并结束。
我只是注意到我还是跳过了一步。
我希望每次迭代都具有一个类似于序列的数组。不要添加printf(“ 0”);和类似的快捷方式。
void print(int combinationlength){
int i,j,count;
int a=combinationlength-1;
int c=combinationlength-1;
int b;
int array[4]={0};
while(array[0]!=1){
array[a]++;
if(array[a]==2){
array[a]=0;
for(b=a;b<=c-1;b--){
if(array[b]==0)
array[b]=1;
}
c--;
}
for(count=0;count<combinationlength;count++){
printf("%d",array[count]);
}
printf("\n");
}
return 0;
}
UPDATED :(也更新了我在此^^代码块上方的解释)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
int i,j,count;
int a=4-1;
int c=4-1;
int b;
int array[4]={0};
while(array[0]!=1){
array[a]++;
if(array[a]==2){
array[a]=0;
for(b=a-1;b>c-1;b--){
if(array[b]==0) array[b]=1;
else array[b]=0;
}
c--;
}
for(count=0;count<4;count++){
printf("%d",array[count]);
}
printf("\n");
}
return 0;
}
硬编码数字4应该是输入变量。
答案 0 :(得分:1)
因此,我仍然不确定我是否完全了解您的需求。如果我理解正确,则需要一定长度的每个位组合(即零和一)。手动在数组中进行加法非常浪费,因此让我们使用CPU已经提供的功能-整数加法。
一个示例程序,打印一定长度的所有组合看起来像这样:
#include <stdio.h>
void print(int len){
for (unsigned long sortOfAnArray = 0; sortOfAnArray < (1U << len); sortOfAnArray++) {
for (int i = len - 1; i >= 0; i--) {
printf("%lu", (sortOfAnArray >> i) & 1);
}
printf("\n");
}
}
int main(void) {
print(5);
return 0;
}
为解释这些步骤,sortOfAnArray
是我们的整数,存储在二进制文件中,我们在每次迭代时都对其加1,以便获得不同的组合。
为了打印它,我们必须单独访问元素,我们将位移和逻辑与(sortOfAnArray >> i) & 1
结合使用。因此,我们将数组中的位向右移动i,并检查它在第一个位置上是否有1,换句话说,我们检查了sortOfAnArray[i]==1
(如果这是一个数组)。
由于标准,我们使用无符号,并且万一您需要多达64位可用的话(尽管long long
在那里更加安全)。
编辑
进一步说明我们如何从整数中提取一位。
假设我们有整数
`unsigned long long foo = 27`
如果我们查看其位表示,则得到00 ... 011011,其中位的总数为64,但是只有很多零,因此是点。现在,假设我们想从右边知道第一位的值。我们可以使用逻辑和运算来找出答案
`foo & 1`
这会将逻辑和应用于两个整数(foo和1)中同一位置的每一对位,在这种情况下,将得出1:
foo -- 00...011011
1 -- 00...000001
foo & 1 -- 00...000001
如果foo的最右边一位为0,则结果为0,因此这实际上使我们可以读取第一位是设置为0还是1。
我们如何将其推广到其他位?
我们有两个选择,我们可以将1中的位移动(1 << n
将1位向左移动n),如果我们使用逻辑,然后,如果foo具有在第n个位置为0;如果它具有1,则为某个非零值(2 ^ n)。
另一种选择是将foo的位向右移动,这样做的好处是,如果foo在第n个位置上为1,则结果现在为1而不是2 ^ n,而如果它为0,结果仍然为0。除此之外,两种方法是等效的。
这是我们提出最终解决方案的方式,即按以下方式访问第n个元素(基于0的计数):
(foo >> n) & 1
我们将foo的位右移n,然后查看第一位是否设置为0或1。本质上,该整数存储64位(当然,我们不需要全部使用它们)与我们在数组中执行此操作的方式相同,但是该方法效率更高。除其他外,我们不需要像您最初尝试的那样为数组实现自己的添加。
答案 1 :(得分:0)
一个整数(大部分时间)已经由4个字节= 32位组成。您可以使用简单的整数而不是数组。
但是以二进制格式打印整数有点棘手,我使用了this question的答案。
#include <stdio.h>
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
(byte & 0x80 ? '1' : '0'), \
(byte & 0x40 ? '1' : '0'), \
(byte & 0x20 ? '1' : '0'), \
(byte & 0x10 ? '1' : '0'), \
(byte & 0x08 ? '1' : '0'), \
(byte & 0x04 ? '1' : '0'), \
(byte & 0x02 ? '1' : '0'), \
(byte & 0x01 ? '1' : '0')
int main(void) {
int a = 0;
int limit = 4;
while( (a & (1 << limit)) == 0)
{
printf("0b"BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(a));
a++;
}
return 0;
}
输出:
0b00000000
0b00000001
0b00000010
0b00000011
0b00000100
0b00000101
0b00000110
0b00000111
0b00001000
0b00001001
0b00001010
0b00001011
0b00001100
0b00001101
0b00001110
0b00001111
小解释:
在while循环中,我使用了所谓的位掩码。 (1 << limit)
在位置limit
处生成二进制1,因此在这种情况下将为0b00010000
。使用二进制&
,我检查a
是否具有该位,如果是,则while循环结束。
答案 2 :(得分:0)
每当我要做一些涉及组合迭代的事情时,我都会自动想到Grey Codes /反向二进制编码。下面是我自己的实现(它使用与Wiki不同的公式,但仍涵盖所有值)。请注意,它们并不是按顺序排列的,但是它确实覆盖了0-> 2 ^ n-1的所有组合,而且速度非常快,因为每次只需更改一个值即可。
#include <stdio.h>
int main(int argc, char** argv) {
unsigned int length = 4;
unsigned int array[4] = {0, 0, 0, 0};
int i, j;
for (i = 0; i < 1 << length; i++) {
array[__builtin_ctz(i)] ^= 1;
printf("Array Values: ");
for (j = 0; j < length; j++) {
printf("%d ", array[j]);
}
printf("\n");
}
return 0;
}
输出:
Array Values: 0 0 0 0
Array Values: 1 0 0 0
Array Values: 1 1 0 0
Array Values: 0 1 0 0
Array Values: 0 1 1 0
Array Values: 1 1 1 0
Array Values: 1 0 1 0
Array Values: 0 0 1 0
Array Values: 0 0 1 1
Array Values: 1 0 1 1
Array Values: 1 1 1 1
Array Values: 0 1 1 1
Array Values: 0 1 0 1
Array Values: 1 1 0 1
Array Values: 1 0 0 1
Array Values: 0 0 0 1
请注意,我使用__builtin_ctz()
方法来快速计数尾随零。我不知道它是否可以在其他任何编译器上实现,但是GCC支持它。
答案 3 :(得分:0)
您的问题陈述令人困惑:
如果添加了1
,则array[3]
的结果为2
,则将其设为0
,然后遍历给定的数组(取反)计数器变量和每个第一个非1
元素设为0
,同时使第一个非1
值之前的所有元素等于0
。
这基本上意味着您希望第一个0
元素保持0
,同时将第一个0
之前的所有元素设置为0
。
结果,数组内容将在{ 0, 0, 0, 0 }
和{ 0, 0, 0, 1 }
之间交替,这可能不是目的。
让我们假设您的问题是模拟一个4位二进制数的base-2计数器,您从0
到8
进行计数。您的代码有点太复杂(双关语;-)。您应该简化并使用更少的索引变量:
#include <stdio.h>
int main() {
int i;
int array[4] = { 0 };
while (array[0] != 1) {
for (i = 0; i < 4; i++) {
printf("%d ", array[i]);
}
printf("\n");
for (i = 4; i-- > 0; ) {
array[i] += 1;
if (array[i] == 2) {
array[i] = 0;
} else {
break;
}
}
}
return 0;
}
输出:
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
请注意如何编写一个从数组的长度开始倒数的for
循环,在使用数组的确切长度并使用正确的测试i-- > 0
时枚举所有有效的索引值适用于有符号和无符号类型。有时将这种技巧称为 downto 运算符,而不是真正的运算符,但可以使之看起来像i --> 0
。
编辑:要打印完整的二进制组合,请继续循环直到i
为-1
:
#include <stdio.h>
int main() {
int i;
int array[4] = { 0 };
for (;;) {
for (i = 0; i < 4; i++) {
printf("%d ", array[i]);
}
printf("\n");
for (i = 4; i-- > 0; ) {
array[i] += 1;
if (array[i] == 2) {
array[i] = 0;
} else {
break;
}
}
if (i < 0) {
/* the array is too small, all combinations exhausted */
break;
}
}
return 0;
}