如何使用C中的递归生成4位二进制组合0,1?

时间:2013-04-22 15:17:08

标签: c algorithm recursion permutation combinations

对于这个数组,尝试这样的事情:

void rollover(int val,int count) {  
    if(count==0) {
        return;
    }
    printf("%d ",val);
    count--;
    rollover(val,count);    
}
int main() {
    int arr[]={0,1};
    for(int i=0;i<=1;i++) {
        rollover(arr[i],4);
    }
    printf("\n");
    return 0;
}

使用递归方法的预期输出:

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

无法理解如何编写该rec函数。我花了几个小时来解决它。 有人可以协助编写该功能吗?

我正在尝试做下面发布的G_G之类的事情。 我怎么能写这样的递归函数? 我是否必须使用一个for循环来调用递归函数,或者使用两个for循环来递归,还是应该调用两次递归函数?例如:

void rollover(int val,int count) {  
    if(count==0) {
        return;
    }
    printf("%d ",val);
    count--;
    rollover(val,count);
    //.. do something if necessary ..
    rollover(val,count);
    //.. do something if necessary ..
}

12 个答案:

答案 0 :(得分:21)

最简单的解决方案:二进制转换,无递归

for(int i = 0; i < 16: ++i) {
    printf("%u%u%u%u", i/8%2, i/4%2, i/2%2, i%2);  
}

有关此循环的递归版本,请参阅MOHAMED's answer


以下解决方案使用的二进制递归

          _ 000
   _ 00 _/
  /      \_ 001
 0        _ 010
  \_ 01 _/
         \_ 011
          _ 100
   _ 10 _/
  /      \_ 101
 1        _ 110
  \_ 11 _/
         \_ 111

使用char*缓冲区的递归解决方案,无二进制转换

void char_buffer_rec(char number[4], int n) {
    if(n > 0) {
        number[4-n] = '0';
        char_buffer_rec(number, n - 1);
        number[4-n] = '1';
        char_buffer_rec(number, n - 1);
    }
    else {
        printf("%s\n", number);
    }
}

用法:

char number[5] = {0};
char_buffer_rec(number, 4);

仅使用int,无缓冲区,无二进制转换的递归解决方案

void int_ten_rec(int number, int tenpower) {
    if(tenpower > 0) {
        int_ten_rec(number, tenpower/10);
        int_ten_rec(number + tenpower, tenpower/10);
    }
    else {
        printf("%04u\n", number);
    }
}

用法:

int_ten_rec(0, 1000);

此解决方案的另一个版本替换tenpower width bitwidth,使用可变填充替换printf width,具体取决于length变量。 length可以定义为新参数,程序常量等。

void int_rec(int number, int bitwidth) {
    static int length = bitwidth;
    int i, n;
    if(bitwidth > 0) {
        int_rec(number, bitwidth-1);
        /* n := 10^(bitwidth-2) */
        for(i=0,n=1;i<bitwidth-1;++i,n*=10);
        int_rec(number + n, bitwidth-1);
    }
    else {
        /* i := number of digit in 'number' */
        for(i=1,n=number;n>=10;++i,n/=10);
        /* print (length-i) zeros */
        for(n=i; n<length; ++n) printf("0");
        printf("%u\n", number);
    }
}

用法:

int_rec(0, 4);

树解决方案,使用char*缓冲区递归,无二进制转换

struct Node {
    int val;
    struct Node *left, *right;
};

void build_tree(struct Node* tree, int n) {
    if(n > 0) {
        tree->left = (Node*)malloc(sizeof(Node));
        tree->right= (Node*)malloc(sizeof(Node));
        tree->left->val = 0;
        build_tree(tree->left, n - 1);
        tree->right->val = 1;
        build_tree(tree->right, n - 1);
    }
    else {
        tree->left = tree->right = NULL;
    }
}

void print_tree(struct Node* tree, char* buffer, int index) {
    if(tree->left != NULL && tree->right != NULL) {
        sprintf(buffer+index, "%u", tree->val);
        print_tree(tree->left, buffer, index+1);
        sprintf(buffer+index, "%u", tree->val);
        print_tree(tree->right, buffer, index+1);
    }
    else {
        printf("%s%u\n", buffer, tree->val);
    }
}

用法:

    char buffer[5] = {0};
    Node* tree = (Node*)malloc(sizeof(Node));
    tree->val = 0;
    build_tree(tree, 4);
    print_tree(tree, buffer, 0);

但是这会在每一行的开头打印一个额外的0,为了避免这种情况,建立两个较小的树:

    Node* tree0 = (Node*)malloc(sizeof(Node));
    Node* tree1 = (Node*)malloc(sizeof(Node));
    tree0->val = 0;
    tree1->val = 1;
    build_tree(tree0, 3);
    build_tree(tree1, 3);
    print_tree(tree0, buffer, 0);
    print_tree(tree1, buffer, 0);

使用int * array的递归解决方案

#define MAX_LENGTH 32
int number[MAX_LENGTH];
void int_buffer_rec(int n, int length) {
    if(n > 0) {
        number[4-n] = 0;
        int_buffer_rec(n - 1, length);
        number[4-n] = 1;
        int_buffer_rec(n - 1, length);
    }
    else {
        for(int i = 0; i < length; ++i) {
            printf("%u", number[i]);
        }
        printf("\n");
    }
}

用法:

int_buffer_rec(4, 4);

答案 1 :(得分:5)

递归可以使用+1

完成
void f(unsigned int x)
{
   printf("%u%u%u%u\n",
          (x>>3)&0x1,
          (x>>2)&0x1,
          (x>>1)&0x1,
          x&0x1);
   if(x==0xF) return;
   else f(x+1);
}

int main(void)
{
    f(0);
}

<强>执行:

$ ./test
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111

答案 2 :(得分:2)

只需遍历DFS深度为4的二叉树,向左移动为0,向右移动为1.

tr(int dep, int val)
{
   if(dep == 4)
   {
     printf("\n");
   }
   else
   {
     printf("%d", val);
     tr(dep+1, 0); // going left
     tr(dep+1, 1); // going right
   }

   return;
}

int main()
{
   tr(0,0);
}

答案 3 :(得分:2)

我试图将我的解决方案限制为使用相同的参数,但我肯定会添加一个额外的参数来了解count的初始值。

void rec(int val, int count) {
    if (count <= 1) {
        int i;
        int f = 0;
        for (i = sizeof(int) * 8; i >= 0; i--) {
            f |= (val >> i) & 1;
            if (f) {
                printf("%d", (val >> i) & 1);
            }
        }
        printf("\n");
    } else {
        rec(val * 2, count - 1);
        rec(val * 2 + 1, count - 1);
    }
}

输出:

1
10
11
100
101
110
111
1000
1001
1010
1011
1100
1101
1110
1111

为了添加前导0,我添加了一个参数:

#include <stdio.h>

void rec2(int val, int count, int b) {
    if (count <= 1) {
        int i;
        for (i = b - 1; i >= 0; i--) {
            printf("%d", (val >> i) & 1);
        }
        printf("\n");
    } else {
        rec2(val * 2, count - 1, b);
        rec2(val * 2 + 1, count - 1, b);
    }
}

void rec(int val, int count) {
    rec2(val, count, count);
}

int main() {
    rec(0, 4);
    rec(1, 4);
    return 0;
}

输出:

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

答案 4 :(得分:1)

让我们从设计递归函数的原型开始。希望它从那里开始有意义。看一下这段代码的非递归版本,你需要相同的变量。您不需要将任何作为参数传递,但我更愿意将它们全部传递,并使解决方案尽可能灵活和模块化。考虑返回值。这应该表明某种成功,以模仿与C标准库的一致性。

int count_r(char *destination, /* The storage for the function to store *
                                *     the 0s and 1s as we count.        */
            size_t length,     /* The number of digits in the number.   */
            char *digit);      /* The set of digits                     */

现在让我们专注于设计第一次迭代。与小学一样,我们首先定义我们的count_r,一次只迭代一位数。一旦我们能够证明它知道如何从0计算到9,我们就会将其引入两位数...但是现在,一次一步。

我们假设在第一次调用之前,destination被初始化为包含length字节的digits[0]。这个初始化由调用者完成,调用者可能会在调用之前输出预先初始化的数组。第一次迭代应该只修改一个字节:由length指示的字节,然后返回给调用者。

int count_r(char *destination, size_t length, char *digit) {
    /* The position of the right-most digit is before the '\0' in destination, *
     *     so we need to decrement length                                      */
    length--;

    /* Find the digit at the very end of destination, within our "digit" parameter */
    char *d = strchr(digit, destination[length]);

    /* d[1] points to the next digit (or '\0') */
    destination[length] = d[1];
    return 0;
}

然后调用者可能会打印数组,并使用相同的缓冲区再次调用count_r来增加计数器。这适用于不同的基础,通过反转digit字符串,我们可以递减而不是递增。但是,正如我们很快就会看到的那样,它在达到可以计入的最高数字后失败:'F'在下面的示例中。

int main(void) {
    char num[] = "0";
    do {
        puts(num);
    } while (count_r(num, strlen(num), "0123456789ABCDEF") == 0);
}

当计时更高时,d [1]将为'\0',因为它将迭代超出数字集并进入字符串的空终止符。让我们考虑添加代码来处理我们的第二次迭代。

需要一些代码将destination[length]设置回第一个digit并递归地向左移动到下一个数字。这发生在d[1] == '\0'时,因此我们可以编写一个if (...) { ... }分支来处理它。

length传入0时会出现问题,我们会在实施刚刚提到的更改后发现这个问题。这是函数返回1以指示计数已完成的位置,因为它已尽可能向左移动并达到可能的最高数量。

void count_r(char *destination, size_t length, char *digit) {
    /* The position of the right-most digit is before the '\0' in destination, *
     *     so we need to decrement length                                      */
    if (length-- == 0) { return 1; }

    /* Find the digit at the very end of destination, within our "digit" parameter */
    char *d = strchr(digit, destination[length]);

    /* d[1] points to the next digit (or '\0') */
    if (d[1] == '\0') {
        /* Set destination[length] to the first digit */
        destination[length] = digit[0];
        /* Recurse onto the next digit. We've already decremented length */
        return count_r(destination, length, digit);
    }

    destination[length] = d[1];
    return 0;
}

在添加一些assert离子(例如assert(strlen(digit) > 1);)并编写一些测试用例之后,我们可能会决定此功能是否已准备好进行生产。我希望我能够提供帮助。 :)

答案 5 :(得分:1)

递归是一种编程技术,它允许程序员根据自己来表达操作。在C和C ++中,这需要自称为的函数的形式。

#include<iostream>
#include<cstdio>
using namespace std;
void rec(int val)
{
  if(val<16)
  {
    printf("%u%u%u%u", val>>3, (val&4)>>2, (val&2)>>1, val&1);
    printf("\n");
    rec(++val);    //calling val+1 here
  }
  return;
}
int main()
{
   rec(0);  //calling recursion for 0
}

这为您提供了您想要的确切输出..!

如果您不想使用位移运算符..

#include<iostream>
#include<cstdio>
using namespace std;
void rec(int val)
{
   if(val<16)
   {
     for(int b=val,a=8,i=0;i<4;b%=a,a/=2,i++)
     printf("%u",(b/a));
     printf("\n");
     rec(++val);// calling val+1 here
   }
   return;
}

int main()
{
   rec(0);//calling recursion for 0
}

答案 6 :(得分:1)

通过使用递归,可以推广此问题以获得任意长度的二进制组合。例如,如果您想获得length=4的所有二进制组合,只需调用printBinaryCombination("????", 0)(即需要将?替换为01) 。

相应的代码如下:

void printBinaryCombination(string str, int current)
{
    int length = str.length();
    if (length == 0)
        return;

    if (current == length)
        printf("%s\n", str.c_str());
    else
    {
        if (str[current] == '?')
        {
            str[current] = '0';
            printBinaryCombination(str, current+1);

            str[current] = '1';
            printBinaryCombination(str, current+1);

            // change back for next time
            str[current] = '?';
        }
        else
            printBinaryCombination(str, current+1);
    }
}

编辑:实际上,上述功能对于处理包含?个随机数的所有二进制组合也很有用,每个组合可以是0或{{ 1}}。例如,如果您致电1,则会打印:

printBinaryCombination("1??0", 0)

答案 7 :(得分:1)

要生成你要求的n位组合(你要求n = 4) 任何n的一般递归实现都是:

主要功能:

vector<string> ve,ve1;
int main(int argc, char const *argv[])
{
    /* code */
    int n;
    cin>>n;
    generate("0",n,true);
    generate("1",n,false);
    for(int i=0;i<ve.size();i++){
        cout<<ve[i]<<endl;
    }
    for(int i=0;i<ve1.size();i++){
        cout<<ve1[i]<<endl;
    }
    return 0;
}

生成以递归方式生成二进制字符串的函数:

void generate(string s,int n,bool b){
    if(n==1){
        if(b==true){
            ve.push_back(s);
        }
        else{
            ve1.push_back(s);
        }
        return;
    }else{
        generate(s+"0",n-1,b);
        generate(s+"1",n-1,b);
    }
}

希望这会有所帮助..

答案 8 :(得分:0)

SOLN 1:更广泛的答案(可在c90,c99下编译)。布尔值输出为int。 限制:
1)使用数学库。(它更重)。

#include<stdio.h>
#include<math.h>
#define MAXBITS 4
//#define MAXVALUES (((int)pow(2,maxb))-1)
const int MAXVALUES = (((int)pow(2,maxb))-1) //if this gives warning then use #define version.

void bin(int val,int total)
{
    int i = 0;          
    if(val <= MAXVALUES)            //can write pow(2,total-1)-1 but anyways..
    {
        for(i =0 ; i < total;i++)
        {
            printf("%d",!!(val&(int)pow(2,total-i-1)));
        }           
        printf("\n");

    }
    else return;
    bin(val+1,total);
}

int main()
{
    setbuf(stdout,NULL);
    bin(0,MAXBITS);//4 bits 
    return 0;
}

Soln 2:这可以通过char打印来完成。没有班次操作员。

限制:
1)它可以(正确)打印最多15(十进制)或0x0F(十六进制)值 2)共计
在堆栈上创建(5 * sizeof(char) * total) + (( total + 2) * (sizeof(int) + sizeof(int)))(非常浪费)。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAXVALUES 15
#define MAXBITS 4
void bin(int val,int total) //@prototype void bin(int val);remove redundant total.
{
    char *s = malloc(sizeof(char)*(total+1)); //cant declare variable array(atleast pre c99)
    int i = 0;
    if(val <= MAXVALUES )
    {
        for(i =0 ; i < total;i++)
        {
        s[total - i-1] = !!(val&(int)pow(2,i)) + '0';
        }
        s[total] = '\0';
        printf("%s\n",s);
    }
    else return;
    bin(val+1,total);
}

int main()
{
    bin(0,MAXBITS);//4 bits 
    return 0;
}

答案 9 :(得分:0)

  

此通用 c ++ 代码适用于任意数量的位。只需将const int num更改为您想要生成二进制代码...

的任意位数
const int num=3;
string code="";

void GenerateBinaryCode(string str,unsigned int n){
    if(n==0){
        cout<<str<<endl;
    }
    else{
        str[num-n]='0';
        GenerateBinaryCode(str,  n-1);
        str[num-n]='1';
        GenerateBinaryCode(str, n-1);
    }
}
int main(){
    for(int i=0; i<num; i++)
        code+="x";

    GenerateBinaryCode(code,num);

}

答案 10 :(得分:0)

这是C语言中的递归实现,它仅使用int 2D数组(无字符串,字符或位移位)来获取任意位长。

static void btable(int* a, int i, int n, int k, size_t len) {
    if (k >= len)
        return;
    for (int j = (i+n)/2; j < n; j++)
        *(a+j*len+k) = 1;
    btable(a,i,(i+n)/2,k+1,len);
    btable(a,(i+n)/2,n,k+1,len);
}

然后您可以使用调用该函数

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int main(void) {

    int n = 4;
    int (*a)[n] = malloc(sizeof(int[(int)pow(2,n)][n]));
    btable(*a,0,pow(2,n),0,n);

    for (int i = 0; i < pow(2,n); i++) { // verify output
        for (int j = 0; j < n; j++)
            printf("%d",a[i][j]);
        printf("\n");
    }

    return 0;
}

答案 11 :(得分:-1)

在提出最终解决方案之前,我将展示两个可用于实现目标的功能。

下一个功能的主要思想是将l1列表的元素添加到l2中包含的每个列表中。例如:

l1 = [0]
l2 = [ [1,1] , [1,0] ]
then 
f1(l1,l2) = [ [0,1,1] ,[0,1,0]]


    def f1(l1:List[Int],l2:List[List[Int]]): List[List[Int]] = l2.map{ r=> l1:::r}

第一个参数是一个列表,其中包含将添加到l2列表中包含的每个数字列表的整数列表。例如:

l1 = [ [0] , [1]]
l2 = [ [1,0], [1,1] ]
f(l1,l2) = [ [0,1,0],[0,1,1], [1,1,0],[1,1,1] ]


    def f(l1:List[List[Int]],l2:List[List[Int]]): List[List[Int]] = l1.map{ r=> f1(r,l2)} flatten

现在,我们有了辅助方法,我们创建了解决需求的函数

/**
n : The max number of digits that the binary number can contain
*/

    def binaryNumbers(n:Int):List[List[Int]] = n match {
     case 1 => List(List(0),List(1))
     case _ => f( List(List(0),List(1)) , binaryNumbers(n-1) )
    }

Example: binaryNumbers(2) = List( List(0,0), List(0,1), List(1,0), List(1,1) )