生成给定长度的1和0的所有可能数组的算法

时间:2011-01-08 11:13:44

标签: c++ algorithm language-agnostic haskell

如何在长度为n的位数组中生成所有可能的位组合。如果我从数组中的所有零开始,则有n种可能性放置第一位,对于这n种可能性,有n-1种可能性来放置第二位。单位所有n位都设置为1。但到目前为止,我没有设法编制它。

也有很多人指出我可以通过从0到(2 ^ n)-1计数并以二进制打印数字来做到这一点。这将是解决问题的简单方法,但是在这种情况下,我只是让机器计数而不是告诉它放置在哪里。我是为了学习而这样做的,所以我想知道如何编制一个放置方法。

6 个答案:

答案 0 :(得分:13)

您如何在纸上手动计算?你会检查最后一位数。如果为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
}

答案 1 :(得分:10)

这些问题在功能上很容易解决。要找到长度为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"]

答案 2 :(得分:1)

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

答案 3 :(得分:1)

答案 4 :(得分:1)

这是我的答案。优点是所有组合都保存在二维数组中,但缺点是你只能使用它来获得长达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;
}

答案 5 :(得分:0)

FredOverflow一般都是正确的。

然而,1s&amp; 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位,或者你必须链接多个整数..并坚持前面的答案:)