English 中文(简体)
How to capture a string into variable in a recursive function?
原标题:

I tried to print all the possible combination of members of several vectors. Why the function below doesn t return the string as I expected?

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;

string EnumAll(const vector<vector<string> > &allVecs, size_t vecIndex, string
        strSoFar)
{
    string ResultString;
    if (vecIndex >= allVecs.size())
    {
        //cout << strSoFar << endl;
        ResultString = strSoFar;
        //return ResultString;
    }
    for (size_t i=0; i<allVecs[vecIndex].size(); i++) {
        strSoFar=EnumAll(allVecs, vecIndex+1, strSoFar+allVecs[vecIndex][i]);
    }
    ResultString = strSoFar; // Updated but still doesn t return the string.
    return ResultString;  

}


int main  ( int arg_count, char *arg_vec[] ) {

    vector <string> Vec1;
          Vec1.push_back("T");
          Vec1.push_back("C");
          Vec1.push_back("A");

    vector <string> Vec2;
          Vec2.push_back("C");
          Vec2.push_back("G");
          Vec2.push_back("A");

    vector <string> Vec3;
          Vec3.push_back("C");
          Vec3.push_back("G");
          Vec3.push_back("T");


     vector <vector<string> > allVecs;

     allVecs.push_back(Vec1);
     allVecs.push_back(Vec2);
     allVecs.push_back(Vec3);




     string OutputString = EnumAll(allVecs,0,"");

     // print the string or process it with other function.
     cout << OutputString << endl;  // This prints nothing why?

     return 0;
}

The expected output is:

TCC
TCG
TCT
TGC
TGG
TGT
TAC
TAG
TAT
CCC
CCG
CCT
CGC
CGG
CGT
CAC
CAG
CAT
ACC
ACG
ACT
AGC
AGG
AGT
AAC
AAG
AAT
最佳回答

Here is an alternate solution. This does not expect you to pass anything but the initial vectors:

int resultSize( vector< vector<string> > vector ){
 int x=1;
 for( int i=0;i<vector.size(); i++ )
  x *= vector[i].size();
 return x;
}

vector<string> enumAll(const vector< vector<string> > allVecs )
{
 //__ASSERT( allVecs.size() > 0 );
 vector<string> result;
 if( allVecs.size() == 1 ){
  for( int i=0 ; i< allVecs[0].size(); i++){
   result.push_back( allVecs[0][i] );
  }
  return result;
 }
 for( int i=0; i<allVecs[0].size(); i++ ){
  for( int j=0; j<resultSize( vector< vector<string> >(allVecs.begin()+1, allVecs.end() ) ); j++){
   result.push_back( allVecs[0][i] + enumAll(vector< vector<string> >(allVecs.begin()+1, allVecs.end() ))[j] );//enumAll on each tempVector is called multiple times. Can be optimzed.
  }
 }
}

Advantage of this method: This is very readable in terms of the recursion. It has easily identifiable recursion base step and also the recursion itself. It works as follows: Each iteration of the recursion enumerates all possible strings from n-1 vectors and the current step simply enumerates them.

Disadvantages of this method: 1. enumAll() function is called multiple times returning the same result. 2. Heavy on stack usage since this is not tail recursion.

We can fix (1.) by doing the following, but unless we eliminate tail recursion, we cannot get rid of (2.).

vector<string> enumAll(const vector< vector<string> > allVecs )
{
 //__ASSERT( allVecs.size() > 0 );
 vector<string> result;
 if( allVecs.size() == 1 ){
  for( int i=0 ; i< allVecs[0].size(); i++){
   result.push_back( allVecs[0][i] );
  }
  return result;
 }
 const vector< vector<string> > tempVector(allVecs.begin()+1, allVecs.end() );
 vector<string> tempResult = enumAll( tempVector );// recurse
 int size = resultSize( tempVector );
 cout << size << " " << tempResult.size() << endl;
 for( int i=0; i<allVecs[0].size(); i++ ){
  for( int j=0; j<size; j++){
   result.push_back( allVecs[0][i] + tempResult[j] );
  }
 }
}
问题回答

You call EnumAll recursively, but you ignore the string that it returns. You have to decide how you are going to aggregate those strings - or what you are going to do with them.

Your function doesn t return anything because your last call doesn t return anything since there s no return and the end of your function.

Edit: One thing that you can do, is to insert your ResultString to a global vector each time before the return. And at the end, all your results will be available in this vector.

Your second return should also accumulate the strSoFar in some way. Something like:

for (size_t i=0; i<allVecs[vecIndex].size(); i++)
{
    strSoFar = EnumAll(allVecs, vecIndex+1, strSoFar+allVecs[vecIndex][i]);
}
ResultString = strSoFar;
return ResultString;

The code you provided crashes. In the following line, notice that you will be exceeding the limits of vecIndex. There is no check on it in the loop. Also, in the if condition above, you donot reset the vecIndex either. So you will have an access violation.

strSoFar = EnumAll(allVecs, vecIndex+1, strSoFar+allVecs[vecIndex][i]);

To fix it, either rest vecIndex in the if() or use the following for statement:

for (size_t i=0; i<allVecs[vecIndex].size() && vecIndex < allVecs.size(); i++){...}

Edit: However, this does not give the correct output yet.

Your function determines all the correct combinations but they are lost since you do not aggregate them properly.

I see you asked the same question here. I will assume you are now looking for a means to get the output back to the top level so you can handle it from there.

The problem then comes down to how you aggregate the output. You are using a string, but are looking for multiple rows of data. There are infinite answers to this .. here is one using a vector container.

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;

void printAll(const vector<string> data);

void EnumAll(const vector<vector<string> > &allVecs, size_t vecIndex, vector<string>&allStr, string strSoFar)
{
    if (vecIndex >= allVecs.size())
    {
      allStr.push_back(strSoFar);
      return;
    }
    for (size_t i=0; i<allVecs[vecIndex].size(); i++)
      EnumAll(allVecs, vecIndex+1, allStr, strSoFar+allVecs[vecIndex][i]);
}


int main  ( int arg_count, char *arg_vec[] ) {

    vector <string> Vec1;
          Vec1.push_back("T");
          Vec1.push_back("C");
          Vec1.push_back("A");

    vector <string> Vec2;
          Vec2.push_back("C");
          Vec2.push_back("G");
          Vec2.push_back("A");

    vector <string> Vec3;
          Vec3.push_back("C");
          Vec3.push_back("G");
          Vec3.push_back("T");


     vector <vector<string> > allVecs;

     allVecs.push_back(Vec1);
     allVecs.push_back(Vec2);
     allVecs.push_back(Vec3);



     vector<string> allStr;
     EnumAll(allVecs,0,allStr,"");

     // print the string or process it with other function.
     printAll(allStr);

     return 0;
}

void printAll(const vector<string> data)
{
  vector<string>::const_iterator c = data.begin();
  while(c!=data.end())
    {
      cout << *c << endl;
      ++c;
    }

}





相关问题
Simple JAVA: Password Verifier problem

I have a simple problem that says: A password for xyz corporation is supposed to be 6 characters long and made up of a combination of letters and digits. Write a program fragment to read in a string ...

Case insensitive comparison of strings in shell script

The == operator is used to compare two strings in shell script. However, I want to compare two strings ignoring case, how can it be done? Is there any standard command for this?

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

String initialization with pair of iterators

I m trying to initialize string with iterators and something like this works: ifstream fin("tmp.txt"); istream_iterator<char> in_i(fin), eos; //here eos is 1 over the end string s(in_i, ...

break a string in parts

I have a string "pc1|pc2|pc3|" I want to get each word on different line like: pc1 pc2 pc3 I need to do this in C#... any suggestions??

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签