Алгоритм генерации всех возможных массивов единиц и нулей заданной длины

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

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

6 ответов


как бы вы посчитали вручную на бумаге? Вы бы проверили последнюю цифру. Если это 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
}

такие проблемы тривиально решаются функционально. Чтобы найти решения длины 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"]

" истинно " рекурсивный подход в 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);
}

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

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


вот мой ответ. Преимущество в том, что все комбинации сохраняются в двухмерном массиве, но недостатком является то, что вы можете использовать его только для жала длиной до 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;
}

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

однако для 1s & 0s вам лучше просто увеличить целое число от 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 бит, или вам придется связать несколько целых чисел.. и придерживайтесь предыдущего ответа:)