嵌套的for循环解决方案

时间:2011-11-03 12:24:30

标签: c++ for-loop nested

我只是出于兴趣而制作了这个程序,并希望让它变得更好。我的问题是我想制作一个嵌套的for循环来执行迭代,但我无法理解它,我已经尝试了很多次,但我的脑袋正在融化。任何帮助将不胜感激。也出于某种原因在windows和openSuse上(从我看到的)程序打印出预期输出后的一些随机字符,解决这个问题将是一个很大的好处。谢谢!

对不起,我没有说清楚,代码的要点是能够理论上生成从AAAAAAAA到ZZZZZZZZ的每个字母组合。

1)不,这不是作业

#include <iostream>
using namespace std;

int main()
{
    char pass [] = {'A','A','A','A','A','A','A','A'};
    while(pass[0] != '[')
    {
        pass[7]++;

        if(pass[7]=='[')
        {
            pass[6]++;
            pass[7] = 'A';
        }
        if(pass[6] == '[')
        {
            pass[6] = 'A';
            pass[5]++;
        }
        if(pass[5] == '[')
        {
            pass[5] = 'A';
            pass[4]++;
        }
        if(pass[4] == '[')
        {
            pass[4] = 'A';
            pass[3]++;
        }
        if(pass[3] == '[')
        {
            pass[3] = 'A';
            pass[2]++;
        }
        if(pass[2] == '[')
        {
            pass[2] = 'A';
            pass[1]++;
        }
        if(pass[1] == '[')
        {

            pass[1] = 'A';
            pass[0]++;
        }

        cout << pass << endl;
    }
    return 0;
}

7 个答案:

答案 0 :(得分:3)

由于(要输出它)使用pass作为C字符串,它应该以null结尾。因为不是,所以打印垃圾。所以你可以把它定义为: char pass [] = {'A','A','A','A','A','A','A','A','\0'}; 或者更简单 char pass[] = "AAAAAAAAA";

答案 1 :(得分:3)

也许是这样的:

const char char_first = 'A';
const char char_last = '[';
const unsigned int passlen = 8;

while (pass[0] != char_last)
{
  ++pass[passlen - 1];

  for (unsigned int i = passlen - 1; i != 0; --i)
  {
    if (pass[i] == char_last)
    {
        ++pass[i - 1]; // OK, i is always > 0
        pass[i] = char_first;
    }
  }
}

要进行打印,请添加<string>并说:

std::cout << std::string(pass, passlen) << std::endl;

我冒昧地将一些魔法数字变成常数。如果你要将它重构为一个单独的函数,你会看到它的优点。

答案 2 :(得分:2)

我忘了继续我自己,只是转换成数字。你在这里做的基本上是打印一个数字范围从'A'到']'的数字,通过ASCII的魔法可以映射到0-28(为什么没有密码?)

打印任何内容的数量,然后真正归结为

#include <iostream>
#include <cmath>

using namespace std;

std::string format(long num, int ndigits) {
        if(ndigits == 0) {
                return "";
        } else {
                char digit = 'A' + num % 28;
                return format(num / 28, ndigits - 1) + digit;
        }
}

int main()
{
        for(int i = 0 ; i < powl(28,8) ; ++i) {
                cout << format(i, 8) << endl;
        }
}

如果您认真对待循环,您可能仍希望在char数组中工作而不是生成十亿个临时字符串,但原则保持不变。

答案 3 :(得分:0)

首先尝试找到表达式中的公共部分,如

    if(pass[7]=='[')
    {
        pass[6]++;
        pass[7] = 'A';
    }

你应该像“这里总是有相同的数字,那里有一个更低的数字”这样的一行。然后,用变量替换数字的概念,找出变量的范围。 KerrekSB为您提供了一个解决方案,尝试从您自己的推理中获得类似的代码。

答案 4 :(得分:0)

你只需要玩一会儿,让它适合一个for循环。

while(pass[0] != '[')变为for (i=0; pass[0] != '['; i++)

然后你可以只用一个替换所有if:

    if(pass[i+1] == '[')
    {

        pass[i+1] = 'A';
        pass[i]++;
    }

我们是如何得出这个结论的?好吧,如果你检查所有的if语句,它们之间的所有变化都是索引。您可以清楚地看到该模式,因此您只需用变量替换索引。

答案 5 :(得分:0)

对于初学者来说,这绝对不是嵌套循环的情况。事实上, 您的整个代码归结为:

pass = initialPattern();
while ( isValidPattern( pass ) ) {
    nextPattern( pass );
    std::cout << pass << std::endl;
}

(但我想知道你是不是真的想在之前做输出 增量。)

现在你所要做的就是定义传递的类型和相关的 功能;你甚至可以考虑 将所有功能都放在一个类中,因为所有功能都在运行 相同的数据实例。

根据您的代码判断,pass应为std::string,且为8 字符;初始化可以写成:

std::string pass( 8, 'A' );

isValidPattern显然只看第一个角色。 (我不是 确定这是正确的,但这就是你的代码所做的。)像:

bool
isValidPattern( std::string const& pattern )
{
    return pattern[0] != '[';
}

根据您的代码,但类似于:

struct NotIsUpper
{
    bool operator()( char ch ) const
    {
        return ! ::isupper( static_cast<unsigned char>( ch ) );
    }
};

bool
isValidPattern( std::string const& pattern )
{
    return pattern.size() == 8
        && std::find_if( pattern.begin(), pattern.end(), NotIsUpper() )
                == pattern.end();
}

似乎更合适。 (当然,如果你正在做任何形式的话 用文本编码,你已经拥有NotIsUpper及其兄弟姐妹 你的工具包。)

最后,nextPattern似乎只是一个多位数 增量,数据以big-endian顺序存储。所以 以下(经典)算法似乎是合适的:

void
nextPattern( std::string& pattern )
{
    static char const firstDigit = 'A';
    static char const lastDigit = 'Z';
    static std::string const invalidPattern( 1, '[' );

    std::string::reverse_iterator current = pattern.rbegin();
    std::string::reverse_iterator end = pattern.rend();
    while ( current != end && *current == lastDigit ) {
        *current = firstDigit;
        ++ current;
    }
    if ( current != end ) {
        ++ *current;
    } else {
        pattern = invalidPattern;
    }
}

正式地,标准中不保证这些字母会 按顺序升序编码,以便最大程度地移植, 实际上你可能应该使用std::vector<int>中的值 范围[0, 26),并将它们映射到仅用于输出的字母。这个 如果你把所有这些操作放在一个类中,那将是微不足道的 内部表示对客户端代码不可见。 类似的东西:

class PatternGenerator
{
    std::vector<int> myData;
public:
    explicit PatternGenerator()
        : myData( 8, 0 )
    {
    }

    void next()
    {
        static int const lastDigit = 26;

        std::vector<int>::reverse_iterator current = pattern.rbegin();
        std::vector<int>::reverse_iterator end = pattern.rend();
        while ( current != end && *current == lastDigit - 1 ) {
            *current = 0;
            ++ current;
        }
        if ( current != end ) {
            ++ *current;
        } else {
            myData.front() = lastDigit;
        }
    }

    bool isValid() const
    {
        return myData.front() < lastDigit;
    }

    friend std::ostream& operator<<(
        std::ostream& dest, PatternGenerator const& obj )
    {
        static char const characterMap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for ( std::vector<int>::iterator current = obj.myData.current();
                current != obj.myData.end():
                ++ current ) {
            dest << characterMap[*current];
        }
        return dest;
    }
};

(注意isValid之类的东西变得更简单,因为它们可以依赖于类不变量。)

鉴于此,您只需编写:

int
main()
{
    PatternGenerator pass;
    while ( pass.isValid() ) {
        std::cout << pass << std::endl;
        pass.next();
    }
    return 0;
}

答案 6 :(得分:0)

要进行嵌套循环,您需要将其从里向外翻。

你编写的代码思路如下:仔细检查最后一个符号的所有可能性,然后更改倒数第二个,然后返回,等等。这就像从1开始计算,到10并且放1在十列等等。

嵌套循环以另一种方式工作:遍历第一个符号的可能性,允许内部循环每次处理其他符号的可能性。即,“按顺序列出所有这些数字,以数百万个地方的0开头,然后以1等开始的数字”。在最外层循环中,您只需为第一个数字设置该值,嵌套循环将处理其余数据。