尝试打印给定变量的每个位组合

时间:2018-06-29 07:02:13

标签: c

让我们说combinationlength = 4。 我的逻辑是在最后一个元素上array {0,0,0,0}添加1,直到第一个元素得到值1。直到添加1array[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应该是输入变量。

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计数器,您从08进行计数。您的代码有点太复杂(双关语;-)。您应该简化并使用更少的索引变量:

#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;
}