如何更好地理解嵌套循环?

时间:2019-04-26 22:36:42

标签: c++ loops for-loop nested nested-loops

我的问题是我对嵌套循环的理解不足以解决此问题。我应该使用嵌套的for循环右对齐在左对齐上生成的堆栈,但是我无法完全确定两个内部条件的条件。

正确答案:

Height = 8
.......#
......##
.....###
....####
...#####
..######
.#######
########

我的答案:

Height = 8
.......#
.......#......#
.......#......#.....#
.......#......#.....#....#
.......#......#.....#....#...#
.......#......#.....#....#...#..#
.......#......#.....#....#...#..#.#
.......#......#.....#....#...#..#.##

我玩过它,认真对待它,没事。我做了(k = 7,k> j,k--),(k = 0,k

应该从用户那里获取一个值,但是我已经在一个单独的文件上对其进行了处理,其中值n是要简化的高度,无需程序的其余部分即可进行处理。

#include <stdio.h>

int main(void) {
    int n = 8;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < i; j++) {
            for(int k = 7; k > j; k--) {
                printf(".");
            }
            printf("#");
        }
        printf("\n");
    }
}

2 个答案:

答案 0 :(得分:4)

实际上非常简单。用每行写一张表格,以及需要打印多少空格和'#'

n == 8

| output   | line | num_spaces | num_signs |
| -------- | ---- | ---------- | --------- |
| .......# | 1    | 7          | 1         |
| ......## | 2    | 6          | 2         |
| .....### | 3    | 5          | 3         |
| ....#### | 4    | 4          | 4         |
| ...##### | 5    | 3          | 5         |
| ..###### | 6    | 2          | 6         |
| .####### | 7    | 1          | 7         |
| ######## | 8    | 0          | 8         |    

对于line,您可以从01n开始,然后向后移动。选择最简单的东西。您将看到从1开始是您的示例中最简单的。

现在,对于每个line,我们需要确定要打印多少num_spacesnum_signs。它们应取决于linen

对于num_spaces,它是n - line;对于num_signs,它是line

因此代码应如下所示:

// for each line
for (int line = 1; line <= n; ++line)
{
    // print n - line spaces

    // print line # characters

    // print \n
}

使用循环,代码将如下所示:

// for each line
for (int line = 1; line <= n; ++line)
{
    // print n - line spaces
    for (int i = 0; i < n -line; ++i)
        std::cout << ' ';

    // print line # characters
    for (int i = 0; i < line; ++i)
        std::cout << '#';

    std::cout << '\n';
}

std::cout.flush();

但是实际上不建议这样做。您可以摆脱那些内部循环。一种简便的方法是使用字符串:

// for each line
for (int line = 1; line <= n; ++line)
{
    // print n - line spaces
    std::cout << std::string(n - line, ' ');

    // print line # characters
    std::cout << std::string(line, '#');

    std::cout << '\n';
}

std::cout.flush();

您甚至可以更进一步:

// for each line
for (int line = 1; line <= n; ++line)
{
    // print n - line spaces and line # characters
    std::cout << std::string(n - line, ' ') << std::string(line, '#') << '\n';
}

std::cout.flush();

答案 1 :(得分:0)

  

我应该将我左对齐的堆栈右对齐   使用嵌套的for循环,但我无法完全弄清楚条件   两个内在的。

我认为,通过使用一些更有意义的变量和函数名称,可以使您的单词问题更容易解决。这些词可能有助于指导您如何思考自己的工作,并且肯定会向读者揭示更多内容。单个字符符号没有什么意义。

另一方面,确实有一些努力可以容忍单个字符名称和变量,但实际上是可以预期的……例如,矩阵数学(也许是计算机生成的图形)经常使用简单地称为x,y的索引,z或t,对于细心的作者不会有任何问题。


我为您准备了4个示例,分别标记为“ X”,“ a”,“ b”和“ c”。每个示例都包装为函子(为方便起见)。

首先,函子“ X”和“ a”是“相同的”,因此我希望编译器生成非常相似的代码。您可能无法一眼确认。区别在于示例'X'具有单个char var和函数名称。例如,“ a”具有多个字母符号,但也没有完整的“正确拼写”单词。

功能说明:

  1. 'X'迭代,返回int 0,步模式cout

    • vars:n,i,j,k

    • 功能:x(),p()

  2. 'a'迭代,返回int 0,步模式cout

    • vars:maxPtrnHgtWdth,步骤

    • 函数:exec(),dotPndLine()

目标:也许这些更长的符号名称可能有助于指导开发工作,或者至少使其更易于阅读。


class T934X_t  // 'X'
{
public:
   int operator()(int64_t n) { return x(n); }

private:
   int x(int64_t n)
      {
         cout << "\n\n\n  int T934X_t()(int64_t) -->"
              << " int x (int64_t)     (" << n
              << ")\n      iterative, return 0, cout step pattern, vars: n, i, j, k    ";

         for (uint i = 0; i < n; ++i) {
            p(n, i+1);
         }
         return 0;
      }
   //                     1..n
   void p (int64_t n, uint j)
      {
         cout << "\n  ";
         for (uint k = 0; k < (n - j); ++k) { cout << '.'; }
         for (uint k = 0; k < j;       ++k) { cout << '#'; }
         cout << ' ' << flush;
      }
}; // class T934X_t



class T934a_t  // 'a'
{
public:
   int operator()(int64_t maxPtrnHgtWdth) { return exec(maxPtrnHgtWdth); }

private:
   int exec (int64_t maxPtrnHgtWdth)
      {
         cout << "\n\n\n  int T934a_t()(int64_t) -->"
              << " int exec (int64_t)     (" << maxPtrnHgtWdth
              << ")\n      iterative, return 0, cout 'step' pattern ";

         for (uint step = 0; step < maxPtrnHgtWdth; ++step) {
            dotPndLine (maxPtrnHgtWdth, step+1);
         }
         return 0; // meaningless
      }
   //                                            1..8
   void dotPndLine (int64_t maxPtrnHgtWdth, uint step)
      {
         cout << "\n  "; //                      8    - 1..8
         for (uint dotCt = 0; dotCt < (maxPtrnHgtWdth - step); ++dotCt) { cout << '.'; }
         for (uint pndCt = 0; pndCt < step;                    ++pndCt) { cout << '#'; }
         cout << " " << flush;
      }
}; // class T934a_t

更多Functor描述:(还需要考虑两个)

  1. 'b':迭代,返回包含步骤模式的字符串

    • vars:maxPtrnHgtWdth,步骤
    • 功能:exec(),dotPndLine()

类似于'a',但是使用stringstream而不是'on-the-fly-cout'。这是一种简单的“延迟”输出技术。我使用它来支持单个输出流(例如cout)的共享(通过多个线程)。

  1. 'c': tail递归,返回包含步进模式的字符串

    • vars:maxPtrnHgtWdth,step,dotct,pndCt
    • 功能:exec(),execR(),dotPndLine(),dotR(),pndR()

之所以加入这个列表是因为我是递归的拥护者,并认为这些相对简单的递归循环示例可能对刚接触递归的人有所帮助。


class T934b_t // 'b'
{
   stringstream ss;
   int64_t maxPtrnHgtWdth;

public:
   string operator()(int64_t a_max)
      {
         maxPtrnHgtWdth = a_max;
         exec ();
         return ss.str();
      }

private:
   void exec ()
      {
         ss << "\n\n\n  string T934b_t()(int64_t) -->"
            << " void exec (int64_t)     (" << maxPtrnHgtWdth
            << ")\n         iterative, return string which contains step pattern";

         for (int64_t step = 0; step < maxPtrnHgtWdth; ++step) // step 0..7
         {
            dotPndLine (step+1); // build each line with dots and pound signs
         }
      }
   //                       1..8
   void dotPndLine (int64_t step)
      {
         ss << "\n  ";  //                           8    - 1..8
         for (int64_t dotCt = 0;  dotCt < (maxPtrnHgtWdth - step); ++dotCt) { ss << '.'; } // dot
         for (int64_t pndCt = 0;  pndCt < step;                    ++pndCt) { ss << '#'; } // pnd
         ss <<  " ";
      }
}; // class T934b_t



class T934c_t // 'c'
{
   stringstream  ss;
   int64_t maxPtrnHgtWdth;

public:
   string operator()(int64_t max)
      {
         maxPtrnHgtWdth = max;
         exec();
         return ss.str();
      }

private:
   void exec ()
      {
         ss << "\n\n\n  string T934c_t()(int64_t): -->"
            << " void exec (int64_t)     (" << maxPtrnHgtWdth
            << ")\n         tail recursive, return string which contains step pattern, ";

         execR (maxPtrnHgtWdth); // entry to recursive code
      }
   //                  8..1
   void execR (int64_t step)
      {
         if (0 >= step) return;  // recursion termination
         dotPndLine (step-1);    // build each line with dots and pound signs
         execR (step-1);         // tail recursion
      }
   //                       7..0
   void dotPndLine (int64_t step)
      {
         ss << "\n  ";
         dotR (step);                 // 7..0  dots
         pndR (maxPtrnHgtWdth-step);  // 1..8  pound sign
         ss << ' ';
      }
   //                 7..0
   void dotR (int64_t dotCt) {
      if (0 >= dotCt) return;  // recursion termination
      ss << '.';
      dotR (dotCt-1);          // tail recursion
   }
   //                 1..8
   void pndR (int64_t pndCt) {
      if (0 >= pndCt)  return; // recursion termination
      ss << '#';
      pndR (pndCt-1);          // tail recursion
   }
}; // class T934c_t

我在单个文件中构建了这4个函子(以及要激活的主要代码和一些简单代码)。

#include <iostream>
using std::cout, std::cerr, std::endl, std::flush;

#include <string>
using std::string, std::stol;

#include <sstream>
using std::stringstream;

#include <cassert>

class T934X_t  // 'X'
{
// ... move previous code here
}    

class T934a_t  // 'a' 
{
// ... move previous code here
}    

class T934b_t // 'b'
{
// ... move previous code here
}    

class T934c_t //  'c'
{
// ... move previous code here
}    

// main invokes the functor
class T934_t
{
public:
   int operator()(int argc, char* argv[])
      {
         if (argc < 2) {
            cerr << "\n  expecting height/width limit: uint > 2\n" << endl;
            return -1;
         }

         if(false) // enable for system info
         {
            string s;
            s.reserve(26000000);
            cout << "\n\n  T934_t()  (implementation details)"       // ubuntu, g++7
                 << "\n  sizeof(long int):  " << sizeof(long int)    //  8 bytes
                 << "\n  sizeof(int64_t) :  " << sizeof(int64_t)     //  8 bytes
                 << "\n  string.size()   :  " << s.size()            //  0 elements
                 << "         sizeof(string) : " << sizeof(string);     // 32 bytes

            for (int i=0; i<1000000; ++i)
               for (char kar='a'; kar<='z'; ++kar)
                  s += kar;

            cout << "\n  string.size()   :  " << s.size()           // 260000 elements
                 << "  sizeof(string) : "  << sizeof(string)        //     32 bytes
                 << endl;
         } // string s destructs here

         // user selected stair step max Pattern Height Width
         int64_t maxPtrnHgtWdth = stol(argv[1]);
         if (maxPtrnHgtWdth < 2)  { maxPtrnHgtWdth = 8; }
         else if (maxPtrnHgtWdth > 80) { maxPtrnHgtWdth = 79; } // arbitrary limit

         return exec (maxPtrnHgtWdth);
      }

private:

   // this functor exec() invokes 'X', 'a', 'b', and 'c'
   int exec (int64_t maxPtrnHgtWdth)
      {
         int retVal = 0;

         // iterative, return 0 ignored, cout step pattern, 
         //     vars: n, i, j, k, functions x(), p()
         (void)T934X_t()(maxPtrnHgtWdth);


         // iterative, return 0 ignored, cout 'step' pattern,
         //     functions exec(), dotPndLine()
         (void)T934a_t()(maxPtrnHgtWdth);


         // iterative, return string which contains step pattern
         cout << T934b_t()(maxPtrnHgtWdth) << flush;


         // tail recursive, returns string which contains step pattern
         cout << T934c_t()(maxPtrnHgtWdth) << flush;


         cout << "\n\n\n  T934_t::exec()"
              << "    (__cplusplus: " <<  __cplusplus  << ")" 
              << std::endl;
         return retVal;
      }
}; // class T934_t


int main(int argc, char* argv[]) { return T934_t()(argc, argv); }