嵌套for循环解决方案
Nested for-loop solution
我做这个程序只是出于兴趣,想把它做得更好。我的问题是,我想做一个嵌套的for循环来执行迭代,但我无法理解它,我已经尝试了很多次,但我的头脑正在融化。任何帮助都将非常感激。此外,由于某些原因,在windows和openSuse上(据我所见),程序在预期输出之后打印出一些随机字符,解决这个问题将是一个很大的奖励。谢谢!
对不起,我没有说清楚,代码的重点是能够理论上生成从AAAAAAAA到ZZZZZZZZ的所有字母组合。
不,这不是作业
#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;
}
可能像这样:
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;
我冒昧地把一些幻数变成了常数。如果您打算将其重构为一个单独的函数,您将看到这样做的优点。
由于(要输出它)您使用pass
作为C字符串,因此它应该以空终止。因为不是,所以打印垃圾。所以你可以把它定义为char pass [] = {'A','A','A','A','A','A','A','A',' '};
或者更简单的char pass[] = "AAAAAAAAA";
我会忘记自己携带,只是转换到/从数字。你在这里所做的基本上是打印一个数字,其数字范围从' 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;
}
}
如果你认真对待循环,你可能仍然想在一个字符数组中工作,而不是产生10亿个临时字符串,但原则是一样的。
首先试着找出表达式中类似
的公共部分 if(pass[7]=='[')
{
pass[6]++;
pass[7] = 'A';
}
你应该沿着这样的思路思考:"这里总是有一个相同的数字,那里总是有一个低一个的数字"。然后,用变量替换数字的概念,找出变量的取值范围。KerrekSB给了你一个解决方案,试着从你自己的推理中得出类似的代码。
你只需要稍微调整一下while,让它适合for循环。
while(pass[0] != '[')
变为for (i=0; pass[0] != '['; i++)
则可以将所有if替换为一个:
if(pass[i+1] == '[')
{
pass[i+1] = 'A';
pass[i]++;
}
我们是如何得出这个结论的?如果你检查所有的if语句它们之间改变的只是指标。你可以很清楚地看到这个模式所以你只需要用一个变量替换下标
对于初学者来说,这绝对不是嵌套循环的情况。事实上,整个代码可以归结为:
pass = initialPattern();
while ( isValidPattern( pass ) ) {
nextPattern( pass );
std::cout << pass << std::endl;
}
(但是我想知道你是不是真的想在增量)。
现在你要做的就是定义pass和relevant的类型函数;你甚至可以考虑将所有内容放入类中,因为所有函数都在相同的数据实例
从你的代码判断,pass
应该是带8的std::string
字符;初始化可以这样写:
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
似乎只是一个多位数增量,其中数据以大端顺序存储。因此,下面的(经典)算法似乎是合适的:
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>
,其值在range [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;
}
要进行嵌套循环,需要将其从内到外翻转。
你是这样写代码的:检查最后一个符号的所有可能性,然后更改倒数第二个符号一次,然后返回,等等。这就像从1开始数到10,然后在十位上加一个1,等等。
嵌套循环以另一种方式工作:遍历第一个符号的可能性,允许内部循环每次处理其他符号的可能性。也就是说,"列出所有的数字,按顺序,在百万个数位中以0开头的,然后是以1开头的,等等"。在最外层的循环中,您只需为第一个数字设置该值,其余部分由嵌套循环处理。
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 是否有可能实现O(N)时间和O(1)空间解决方案,以实现C++中的字符串循环移位
- C++ 循环屏障中的倒计时使用原子变量出错[请无锁的解决方案]
- 只有一个正确解决方案的无限循环
- 高速解决方案以循环浏览不同变量的所有组合,并使用启动步骤停止方案(C )
- 如果找不到解决方案,我如何留下递归循环,而不会打印任何东西
- 卡死胡同-无休止的循环,没有解决方案
- 对于同一循环的这两个连续组,是否有更有效的解决方案
- 循环查找解决方案
- 简单的尝试 c++ 的捕获循环解决方案
- 用于交替 for 循环的 C++ 通用解决方案
- 在c++中,任何更好的方法都可以做到这一点,计算谜题的解决方案(49!结果,49个循环)
- 一个while循环的重要解决方案
- 如果-否则循环以找到解决方案
- 在一个文件夹(及其子文件夹)的所有文件上循环:最简单的解决方案
- 嵌套for循环解决方案
- 需要一个解决方案c++循环和条件
- 寻找最优雅的循环特定字符串的解决方案