C: комбинации 0 и 1 с использованием рекурсии

Я хочу перечислить комбинации o & 1 рекурсивно, используя c, в зависимости от количества (числа) переменных

результат, который я хочу, это

000
001
010
011
100
101
110
111

Я пробовал много алгоритмов, последний из них:

void permute(unsigned number)    {

    if(number == 0) {
        printf("\n");
        return;
    }

    permute(number - 1);
        printf("0");
    permute(number - 1);
        printf("1");


}   //permute ends here


void permuteN(unsigned number) {

    unsigned i;

    for(i = 0; i < number + 1; i++){
        permute(i);
    }
}   //permuteN ends here

Я думаю, что это дает мне ответ, но не заказан, потому что я не знаю, куда положить \ n;

нужна ваша помощь!


person Ahmed Aljazzar    schedule 12.11.2012    source источник
comment
Это не перестановки, это комбинации.   -  person Matteo Italia    schedule 13.11.2012
comment
@MatteoItalia Нет, согласно Википедии и моей памяти, вам нужны комбинации, когда порядок не важен. В этом случае важен четкий порядок (001 отличается от 010 или 100)   -  person madth3    schedule 13.11.2012
comment
Фактически, это троичное декартово произведение: en.wikipedia.org/wiki/Cartesian_product#n- ary_product   -  person Thomas    schedule 13.11.2012
comment
@ madth3 Перестановка - это изменение порядка значений в наборе. Комбинация - это когда вы берете любые значения в наборе. Если вы переставляете 001, единственными вариантами будут 001, 010 и 100.   -  person paddy    schedule 13.11.2012
comment
@paddy Я не сказал, что это были перестановки, я просто указал, что это тоже не комбинации: en.wikipedia.org / wiki / Комбинация. В некоторых кругах я видел, что это называется перестановками с повторением, но это уже другая история.   -  person madth3    schedule 13.11.2012
comment
Есть ваш вопрос: как я могу напечатать все комбинации 0 и 1 с заданной шириной, используя рекурсивную функцию (ы)?   -  person Morpfh    schedule 13.11.2012
comment
@Morpfh да, это то, что я хочу   -  person Ahmed Aljazzar    schedule 13.11.2012


Ответы (3)


Все, что вы на самом деле делаете, это преобразование числа в двоичное ... Простой цикл делает это без каких-либо библиотечных вызовов (кроме _1 _) ...

const unsigned int numbits = 3;
unsigned int bit;

for( bit = 1U << (numbits-1); bit != 0; bit >>= 1 ) {
    printf( number&bit ? "1" : "0" );
}
printf( "\n" );

Отредактировано, поскольку вам кажется, что вам нужна рекурсия. У вас должен быть способ указать, сколько битов вам нужно. Вам нужно передать это в свою рекурсивную процедуру:

#include <stdio.h>

void permute(unsigned number, unsigned bits)
{
    if( bits == 0 ) return;
    permute(number / 2, bits-1);
    printf( "%d", number % 2 );
}   //permute ends here


void permuteN(unsigned number, unsigned bits ) {

    unsigned i;

    for(i = 0; i < number + 1; i++){
        permute(i, bits);
        printf("\n");
    }
}   //permuteN ends here

int main(void)
{
    permuteN(7, 3);
    return 0;   
}

Чтобы получить результат в нужном вам порядке, вы не можете знать, когда писать новую строку. В этом случае вы пишете это потом.

person paddy    schedule 12.11.2012

Если вы действительно просто ищете комбинации 1 и 0, я предлагаю вам просто подсчитать числа и перечислить их в двоичном формате.

Возьмите числа 0...7 в двоичном формате и взяв только последние 3 бита (возможно, примените маску), и вы получите тот же набор, который вы указали:

000
001
...
...
111

Для n-значных комбинаций необходимо выполнить 0..2^n - 1


На основе этого ответа для одного конкретного случая из 3- биты (Благодарим @ChrisLutz и @dirkgently)

#include <stdio.h>
int main(){
int numdigits = 3, j;
    for(j=1; j<8; j++)
        printbits(j);
}

void printbits(unsigned char v) {
  int i;
  for(i = 2; i >= 0; i--) putchar('0' + ((v >> i) & 1));
  printf("\n");
}

Вывод:

000
001
010
011
100
101
110
111
person Anirudh Ramanathan    schedule 12.11.2012
comment
Я знаю эту идею, но это не то, что я хочу - person Ahmed Aljazzar; 13.11.2012

У @paddy есть хороший ответ; только добавление немного (что касается моих крутых моментов, судя по вашему ответу на мой комментарий - немного опоздал в игру). Это полагается на pow (), (и log10 для некоторой аккуратности в печати), тем не менее; при использовании компиляции gcc с -lm:

base здесь может немного сбить с толку, но думаю, вы уловили смысл.

gcc -Wall -Wextra -pedantic -o combo combo.c -lm

/* gcc - Wall -Wextra -pedantic  -o combo combo.c -lm */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

static void prnt_combo(unsigned number, unsigned bits, int base)
{
    if (!bits)
        return;
    prnt_combo(number / base, --bits, base);
    printf("%d", number % base);
}


void prnt_combos(int bits, int base)
{
    int i;
    int n = pow(base, bits);
    int wp = log10(n) + 1;

    fprintf(stderr,
        "Printing all combinations of 0 to %d by width of %d numbers. "
        "Total %d.\n",
        base - 1, bits, n
    );

    for (i = 0; i < n; i++) {
        fprintf(stderr, "%*d : ", wp, i);
        prnt_combo(i, bits, base);
        printf("\n");
    }
}


/* Usage: ./combo [<bits> [<base>]]
 *        Defaults to ./combo 3 2
 * */
int main(int argc, char *argv[])
{
    int bits = argc > 1 ? strtol(argv[1], NULL, 10) : 3;
    int base = argc > 2 ? strtol(argv[2], NULL, 10) : 2;

    prnt_combos(bits, base);
    return 0;
}

Образец:

$ ./combo 4 2
Printing all combinations of 0 to 1 by width of 4 numbers. Total 16.
 0 : 0000
 1 : 0001
 2 : 0010
 3 : 0011
 4 : 0100
 5 : 0101
 6 : 0110
 7 : 0111
 8 : 1000
 9 : 1001
10 : 1010
11 : 1011
12 : 1100
13 : 1101
14 : 1110
15 : 1111

Или чистый вывод:

$ ./combo 3 2 >&2-
000
001
010
011
100
101
110
111

Вы можете добавить что-то вроде:

if (base > 10)
    printf("%x", number % base);
else
    printf("%d", number % base);

в prnt_combo(). Таким образом, к 2 16 вы получите:

    0 : 00
    1 : 01
    2 : 02
    3 : 03
    4 : 04
  ...
  250 : fa
  251 : fb
  252 : fc
  253 : fd
  254 : fe
  255 : ff
person Morpfh    schedule 12.11.2012
comment
чем ты за то, что подарил мне еще одну хорошую идею - person Ahmed Aljazzar; 13.11.2012