我正在尝试制作一个需要嵌套循环才能正常工作的程序。 但是嵌套循环的数量取决于用户输入的字符数以及要输出的字符。
到目前为止,这是我的代码。
#include<iostream>
using namespace std;
int main(){
string str;
cout<<"Enter some string: ";
cin>>str;
// for two characters
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2 ; j++){
cout<<str[i]<<str[j]<<endl;
}
};
// for four characters
for(int i = 0; i<4; i++){
for(int j=0;j<4;j++){
for(int k =0;k<4;k++){
for(int z=0;z<4;z++)
cout<<str[i]<<str[j]<<str[k]<<str[z]<<endl;
}
}
}
return 0;
}
所以,有什么办法可以解决这个问题。
答案 0 :(得分:6)
您需要动态地进行操作:
std::vector<unsigned int> offsets(s.size());
bool isContinue;
do
{
for(auto offset : offsets)
{
std::cout << s[offset];
}
std::cout << std::endl;
isContinue = false;
for(auto offset = offsets.rbegin(); offset != offsets.rend(); ++offset)
{
if(++*offset < s.size())
{
isContinue = true;
break;
}
*offset = 0;
}
}
while(isContinue);
背后的想法就像递增计数(十进制):达到9后,就递增下一位。同样,向量中的每个偏移量代表一个循环变量,在“溢出”时,增加下一个偏移量,一旦最重要的偏移量“溢出”,我们就完成了。
高性能变体(使用goto
,保留一个比较和条件变量):
std::vector<unsigned int> offsets(s.size());
NEXT:
for(auto offset : offsets)
{
std::cout << s[offset];
}
std::cout << std::endl;
for(auto offset = offsets.rbegin(); offset != offsets.rend(); ++offset)
{
if(++*offset < s.size())
goto NEXT;
*offset = 0;
}
答案 1 :(得分:3)
有两种基本的方法可以进行循环。
第一个是显式的:您需要使用索引数组,而不是循环索引的单个变量。然后,在每个步骤中,您都增加最后一个索引,当该索引超过限制时,将其重置并增加上一个索引:
int n = str.size(); // Get rid of unsigned
std::vector<int> index(n);
for(;;) {
// Generate output
for (int i=0; i<n; i++) {
std::cout << str[index[i]];
}
std::cout << std::endl;
// Increment
int i = n-1; // start from last index
while (i>=0 && index[i] == n-1) {
// I-th index has reached the end of the string, flip over to 0
index[i] = 0;
--i;
}
if (i == -1) break; // all of them returned to 0... that's all, folks
index[i] += 1;
}
第二种方法是使用递归,例如,使用接受部分字符串作为参数构建的函数,并且如果此前缀不完整,则会遍历字符串并通过扩展前缀调用自身:
std::function<void(const std::string&)> proc = [&](const std::string& prefix) {
if (prefix.size() == str.size()) {
// Prefix is complete, just output result
std::cout << prefix << std::endl;
} else {
// Extend the prefix and call yourself for the nested loops
for (int j=0; j<n; j++) {
proc(prefix + str[j]);
}
}
};
proc("");
递归方法更紧凑,但要花一些时间才能适应,在某些情况下可能会出现问题。
避免嵌套循环的另一种方式是使用简单的计数和数学运算...编写一个返回您要查找的第n个字符串而无需循环前一个字符串的函数很容易...
for (int i=0,loops=pow(n, n); i<loops; i++){
std::string s = "";
int k = i;
for (int j=0; j<n; j++) {
s = str[k % n] + s;
k /= n;
}
std::cout << s << std::endl;
}
答案 2 :(得分:0)
让我们将所有N个嵌套循环折叠成一个嵌套循环。首先,我们需要N个索引,这些索引会适当增加:
class Multiindex
{
public:
Multiindex(int size, int last_) : idx(size,0), last(last_) {}
void inc()
{
for (int i = idx.size() - 1; i >= 0; --i) {
if (idx[i] == last - 1) {
idx[i] = 0;
if (i == 0) complete = true;
}
else {
++idx[i];
break;
}
}
}
const auto& getIdx() const { return idx; }
const auto isComplete() const { return complete; }
private:
std::vector<int> idx;
int last;
bool complete = false;
};
这是multiindex类的最小示例。如果嵌套循环中需要不同的索引,也可以编写decrement
方法或使用最后一个索引的向量。
现在一切准备就绪,可以替换嵌套循环了:
std::string s;// From user
Multiindex midx(s.length(), s.length());
while (!midx.isComplete()) { // Your nested loop
const auto& idx = midx.getIdx();
for (int i = 0; i < idx.size(); ++i) { // Replacement for cout << s[i] << s[j] << ... << s[z] << endl;
std::cout << s[idx[i]];
}
std::cout << std::endl;
midx.inc();
}