我有两个组(A)和(B)以及一些变量abcde ...(> 2)来分组,至少一个变量在组(A)中,一个在组中(B)。该程序应打印出所有组合。输出的顺序并不重要。
对于3个变量“abc”结果应为:
A | B
-------
ac | b
ab | c
bc | a
a | bc
b | ac
c | ab
我写的程序是:
#include <string>
#include <stdio.h>
using namespace std;
string gencombinations(string , string );
string removeCharsFromString( string , string);
int main(){
string result;
string a = "";
string b = "";
string batch = "abc";
a = batch;
cout << "batch \ta = {"; cout << a; cout << "},\t batch b = {"; cout << b; cout << "}\t"; cout << endl;
result = gencombinations(a, b);
//cout << result << endl;
return 0;
}
string gencombinations(string a, string b){
string _tmp;
string _tmp2;
for(int i = 0; i < a.size(); i++ ) {
_tmp = a.at(i+1);
b = _tmp+b;
cout << "remove \t {"; cout << _tmp; cout << "},\t\t from a = {"; cout << a; cout << "}\t"; cout << endl;
a= removeCharsFromString( a, _tmp );
cout << "batch \ta = {"; cout << a; cout << "},\t batch b = {"; cout << b; cout << "}\t"; cout << endl;
if(a.size() > 1)
_tmp2 = gencombinations(a, b);
if(_tmp2 != "") return _tmp2;
b = removeCharsFromString( b, _tmp );
}
return _tmp2;
}
string removeCharsFromString( string str, string charsToRemove ) {
for (int i = 0; i < charsToRemove.length(); ++i ) {
//cout << "charsToRemove = {"; cout << charsToRemove.at(i); cout << "},\t From String = {"; cout << str; cout << "}\t"; cout << endl;
std::string::size_type s = str.find(charsToRemove.at(i));
if (s != std::string::npos)
str.erase(i+1, 1);
}
return str;
}
给出了输出:
batch a = {abc}, batch b = {}
remove {b}, from a = {abc}
batch a = {ac}, batch b = {b}
remove {c}, from a = {ac}
batch a = {a}, batch b = {cb}
然后休息。 (开头的批次B中没有变量没问题。)
摆脱out_of_range
(来自@Paul的答案)我得到:
string gencombinations(string a, string b){
string _tmp;
string _tmp2;
string _resul;
for(int i = 0; i < a.size(); i++ ) {
_tmp = a.at(i);
b = _tmp+b;
if(a.size() > 1)
a= removeCharsFromString( a, _tmp );
cout << "batch \ta = {"; cout << a; cout << "},\t batch b = {"; cout << b; cout << "}\t"; cout << endl;
if(a.size() > 1){
cout << "recursion" << endl;
_tmp2 = gencombinations(a, b);
}
if(_tmp2 != "") {
return _tmp2;
cout << "_tmp2 is empty" << endl;
}
b = removeCharsFromString( b, _tmp );
a = _tmp;
}
return _tmp2;
}
string removeCharsFromString( string str, string charsToRemove ){
for (int i = 0; i < charsToRemove.length(); ++i ) {
std::string::size_type s = str.find(charsToRemove.at(i));
if (s != std::string::npos)
str.erase(i, 1);
}
return str;
}
输出:
batch a = {bcd}, batch b = {a}
recursion
batch a = {cd}, batch b = {ba}
recursion
batch a = {d}, batch b = {cba}
如何正确递归?
答案 0 :(得分:3)
这一行:
for(int i = 0; i < a.size(); i++ ) {
_tmp = a.at(i+1);
包含逻辑错误。与任何其他类型的数组或向量一样,字符串在c ++中基于0。在某些时候,代码尝试从数组中读取字符串结尾后的第一个char。此时程序将抛出一个out_of_range
- 异常(只需用try-catch包装该行来自己观察)。
至于你的代码:我不太了解tmp2
的目的。代码中没有明确创建tmp2
的行,因此它总是&#34;&#34;,与输入无关。
但实际上有更简单的解决方案,而不是在a
到b
的任意时间移动每个角色,这也会产生重复。相反,您可以使用以下简化之一:
使用0和1的排列,其中0表示将char放在a
中,1表示将char放在b
中:
void gencombinations(string allchars){
for(unsigned int permute = 0 ; permute < (1 << allchars.size()) ; permute++){
string a, b;
for(unsigned int bit = 0 ; bit < allchars.size() ; bit++)
if(permute & (1 << bit))
a += allchars[bit];
else
b += allchars[bit];
cout << "batch: a = {" + a + "}, b: {" + b + "}" << endl;
}
}
请注意,此解决方案仅适用于特定大小的输入字符串。 permute
的bitcount确定输入字符串的最大长度。例如。 32位的数据类型允许最大长度为32的输入字符串。对于大于64的输入字母表,需要解决此基本解决方案。
使用递归方法调用和fork,其中一个调用将char添加到a
,将一个调用添加到b
:
gencombinations(string chars , string a , string b){
if(chars.size()){
char c = chars[0];
chars.erase(0 , 1);
gencombinations(chars , a + c , b);
gencombinations(chars , a , b + c);
}else
cout << "batch: a = {" + a + "}, b = {" + b + "}";
}
答案 1 :(得分:2)
您不必删除任何内容。只需继续从批处理中构建组字符串a
和b
,直到批处理已经过量。
当然,您必须为批处理中的每个字母考虑两种情况:它要么进入A组,要么进入B组。当您递归时,您必须为每种情况分叉递归。您还必须从批处理中删除当前字母,但这很容易,因为它是字符串中的第一个字母:
#include <string>
#include <iostream>
using namespace std;
void combo(string batch, string a, string b)
{
if (batch.size() == 0) {
if (a.size() && b.size()) {
cout << a << " :: " << b << "\n";
}
} else {
combo(batch.substr(1), a + batch[0], b);
combo(batch.substr(1), a, b + batch[0]);
}
}
int main()
{
combo("abc", "", "");
return 0;
}
此解决方案只是在递归的底层打印字符串。您也可以将它们附加到字符串流或字符串。