简体   繁体   中英

Recursion in c++ (generate binary codes)

I am trying to write a program that generates all the binary codes given an input number (for the number of bits). For example, if the user inputs 3, it should generate all the numbers below:

000
001
010
011
100
101
110
111

The function is called generateBinaryCode(), and it has to be recursive (that's the challenge of the question).

The following is my attempt but it doesn't work. Can anyone please offer me some insights?

Thanks in advance.

#include <iostream>
#include <string>
#include <vector>

using namespace std;
vector<string> generateBinaryCode(int nBits);

int main()
{
    int input;

    while (true)
    {
        cout << "Enter an integer (any negative numbers are sentinel): ";
        cin >> input;
        if (input < 0) break;

        for (unsigned i = 0; i < generateBinaryCode(input).size(); i++)
            cout << generateBinaryCode(input).at(i) << endl;
    }

    return 0;
}

vector<string> generateBinaryCode(int nBits)
{
    vector<string> result;
    int size = result.size();
    std::vector<string>::iterator it;

    if (nBits == 1) {

        result.push_back("0");
        result.push_back("1");

    } else {
        result = generateBinaryCode(nBits - 1);

        for (unsigned int i = 0; i < result.size(); i++)
        {
            result.push_back("0" + result.at(i));
            result.at(i) = "1" + result.at(i);
        }

    }

    return result;
}

The main flaw is in the following loop:

    for (unsigned int i = 0; i < result.size(); i++)
    {
        result.push_back("0" + result.at(i));
        result.at(i) = "1" + result.at(i);
    }

In a nutshell, you don't want to be adding elements to result while iterating over it. What you have right now is an infinite loop (that'll eventually run out of memory).

Also, you don't want to be calling generateBinaryCode() at every iteration of your main loop. Call it once and store the result in a variable.

And finally (and least importantly), entering 0 at the prompt will result in infinite recursion.

Your code is very close to correct, but the self-modifying result is going to be problematic. insertion into a vector does many things, among them invalidating iterators currently open on the sequence. But it will also change the result of size() (for obvious reasons, I hope).

The simplest answer is to use a sub list vector, then enumerate that , appending all entries within with '0' and '1', and inserting those results into your return vector. An example of this is below:

std::vector<std::string> getBitStrings(unsigned int n)
{
    std::vector<std::string> result;

    if (n <= 1)
    {
        result.push_back("0");
        result.push_back("1");
    }
    else
    {   // recurse, then add extra bit chars
        std::vector<std::string> sub = getBitStrings(n-1);
        for (std::vector<std::string>::const_iterator it = sub.cbegin();
             it != sub.cend(); ++it)
        {
            result.push_back(*it+'0');
            result.push_back(*it+'1');
        }
    }
    return result;
}

This is somewhat different than your implementation, in that it expects values between 1 and n for the bit count. Running with n=5 , the following is produced:

int main()
{
    std::vector<std::string> bs = getBitStrings(5);
    std::copy(bs.begin(), bs.end(), 
         std::ostream_iterator<std::string>(std::cout, "\n"));
    return 0;
}

Output

00000
00001
00010
00011
00100
00101
00110
00111
01000
01001
01010
01011
01100
01101
01110
01111
10000
10001
10010
10011
10100
10101
10110
10111
11000
11001
11010
11011
11100
11101
11110
11111

To be honest there are a plethora of ways this can be done, this is just one. I purposely modeled it after your original implementation so as to limit algorithm change. I hope it helps you understand the problem and one way around it.

What you are trying to do at this line

result.push_back("0" + result.at(i));

is basically this , and that may be dodgy, and cause of your problem.

simpler and concise solution

void printBin(std::string prefix, int n)
{
    if(prefix.size() == n)
    {

        std::cout <<prefix <<std::endl;
        return;
    }

    printBin(prefix + '0', n);
    printBin(prefix + '1', n);

    return;

}

int main()
{
    int n;
    std::cin >> n;
    printBin("", n);
    return 0;
 }

Here's a simple one:
(written in C, not C++, but the outline should be the same)

void generateBinaryCode(char* txt, int i, int len)
{
    if (len != 0)
    {   txt[i] = '0';
        makeBinary(txt, i+1, len-1);

        txt[i] = '1';
        makeBinary(txt, i+1, len-1);
    } else
    {
        puts(txt);
    }
}


int main()
{
    char str[4] = {0};

    generateBinaryCode(str, 0, sizeof(str)-1);

    getchar();
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM