Алгоритм генерации всех возможных массивов единиц и нулей заданной длины - PullRequest
8 голосов
/ 08 января 2011

Как мне сгенерировать все возможные битовые комбинации в массиве битов длины n. Если я начну со всех нулей в моем массиве, тогда будет n возможностей разместить первый бит, и для этих n возможностей есть n-1 возможностей разместить второй бит. Но до сих пор мне не удалось запрограммировать это.

Также многие люди указали, что я могу сделать это, считая от 0 до (2 ^ n) -1 и печатая число в двоичном виде. Это был бы простой способ решить проблему, однако в этом случае я просто позволил машине считать, а не указывал, где ее разместить. Я делаю это для обучения, поэтому мне хотелось бы узнать, как запрограммировать подход с размещением.

Ответы [ 6 ]

13 голосов
/ 08 января 2011

Как бы вы посчитали вручную на бумаге? Вы бы проверили последнюю цифру. Если это 0, вы устанавливаете его на 1. Если это уже 1, вы устанавливаете его обратно на 0 и переходите к следующей цифре. Так что это рекурсивный процесс.

Следующая программа генерирует все возможные комбинации, изменяя последовательность:

#include <iostream>

template <typename Iter>
bool next(Iter begin, Iter end)
{
    if (begin == end)      // changed all digits
    {                      // so we are back to zero
        return false;      // that was the last number
    }
    --end;
    if ((*end & 1) == 0)   // even number is treated as zero
    {
        ++*end;            // increase to one
        return true;       // still more numbers to come
    }
    else                   // odd number is treated as one
    {
        --*end;            // decrease to zero
        return next(begin, end);   // RECURSE!
    }
}

int main()
{
    char test[] = "0000";
    do
    {
        std::cout << test << std::endl;
    } while (next(test + 0, test + 4));
}

Программа работает с любой последовательностью любого типа. Если вам нужны все возможные комбинации одновременно, просто поместите их в коллекцию, а не распечатывайте. Конечно, вам нужен другой тип элемента, потому что вы не можете поместить массивы C в вектор. Давайте используем вектор строк:

#include <string>
#include <vector>

int main()
{
    std::vector<std::string> combinations;
    std::string test = "0000";
    do
    {
        combinations.push_back(test);
    } while (next(test.begin(), test.end()));
    // now the vector contains all pssible combinations
}

Если вам не нравится рекурсия, вот эквивалентное итеративное решение:

template <typename Iter>
bool next(Iter begin, Iter end)
{
    while (begin != end)       // we're not done yet
    {
        --end;
        if ((*end & 1) == 0)   // even number is treated as zero
        {
            ++*end;            // increase to one
            return true;       // still more numbers to come
        }
        else                   // odd number is treated as one
        {
            --*end;            // decrease to zero and loop
        }
    }
    return false;              // that was the last number
}
10 голосов
/ 08 января 2011

Такие проблемы тривиально решаются функционально. Чтобы найти решения длины n, вы сначала находите решения длины n-1, а затем добавляете '0' и '1' к этим решениям, удваивая пространство решений.

Вот простая рекурсивная программа на Haskell:

comb 0 = [[]]

comb n =
    let rest = comb (n-1)
    in  map ('0':) rest
     ++ map ('1':) rest

А вот и тестовый прогон:

> comb 3
["000","001","010","011","100","101","110","111"]
1 голос
/ 24 мая 2011

Это мой ответ.Преимущество состоит в том, что все комбинации сохраняются в двумерном массиве, но недостатком является то, что вы можете использовать его только для длины строки до 17 цифр !!

#include <iostream>

using namespace std;

int main()
    {
    long long n,i1=0,i2=0, i=1, j, k=2, z=1;
    cin >> n;
    while (i<n){
        k = 2*k;
        i++;
    }
    bool a[k][n], t = false;
    j = n-1;
    i1=0;
    i2 = 0;
    z = 1;
    while (j>=0){
        if(j!=n-1){
        z=z*2;
        }
        i2++;
        t = false;
        i = 0;
    while (i<k){
        i1 = 0;
        while (i1<z){
            if(t==false){
            a[i][j]=false;
            }
            else {
                a[i][j]= true;
            }
            i1++;
            i++;
        }
        if(t==false){
            t = true;
        }else {
            t = false;
        }
    }
    j--;
    }
    i = 0;
    j = 0;
    while (i<k){
        j = 0;
        while (j<n){
            cout << a[i][j];
            j++;
        }
        cout << endl;
        i++;
    }
    return 0;
}
1 голос
/ 14 января 2011

Оптимальное решение здесь:

http://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation

1 голос
/ 08 января 2011

«действительно» рекурсивный подход в C ++:

#include <iostream>
#include <string>

void print_digits(int n, std::string const& prefix = "") {
    if (!n) {
        std::cout << prefix << std::endl;
        return;
    }
    print_digits(n-1, prefix + '0');
    print_digits(n-1, prefix + '1');
}

int main(int, char**) {
    print_digits(4);
}
0 голосов
/ 08 января 2011

FredOverflow в целом прав.

Однако для 1 и 0 лучше всего увеличить целое число от 0:

int need_digits = 10
unsigned int i=0
while (! i>>need_digits){
    # convert to binary form: shift & check, make an array, or cast to string, anything.
    }

... я думаю, вам не понадобится больше 32 бит, иначе вам придётся соединить несколько целых чисел .. и придерживаться предыдущего ответа :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...