【问题标题】:Correct way to write a pattern in C language [closed]用 C 语言编写模式的正确方法 [关闭]
【发布时间】:2017-05-17 10:04:01
【问题描述】:

我想得到以下输出:

1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9 10

运行的代码如下:

#include <stdio.h>

int main(void) {
    int i=1,flag=0,lines=0;  //0 for forward, 1 for reverse
    while(i!=0 && lines<3){
        if(!flag){
            printf("%d ",i);
            if(i==10){
                flag=1;
                printf("\n");
                lines++;
            }
            else
                i++;
        }
        else if(flag){
            printf("%d ",i);
            if(i==1){
                lines++;
                flag=0;
                printf("\n");
            }
            else
                i--;
         }
    }
    return 0;
}

我从上述代码中获得了所需的输出,但不确定它是否是最佳代码。还有其他方法/建议吗?考虑到无限空间,但时间复杂度应保持最低。

条件:只使用一个循环

【问题讨论】:

  • 你应该考虑发帖到codereview.stackexchange.com而不是代码审查问题
  • for( int i = 1; i &lt;= 3; i ++ ) { if( i % 2 ) for( int j = 1; j &lt;= 10; j++ ) printf( "%d ", j ); else for( int j = 10; j &gt;= 1; j-- ) printf( "%d ", j ); printf("\n"); }
  • 我投票结束这个问题,因为它属于codereview.stackexchange.com
  • @taskinoor 仅仅因为一个问题在其他地方是热门话题,并不会使它在此处脱离话题。这已在 meta 上多次讨论过。代码审查确实是一个更适合发布此内容的网站,但这并不会使这个问题在 SO 上偏离主题。
  • 在没有特定系统的情况下讨论性能毫无意义。特别是因为在这种情况下 99% 的执行时间将被 printf 函数调用阻塞。除非您将算法与 printf 调用分开,否则尝试优化此循环只不过是“未成熟的优化”。优化还包括尝试在编译时预先生成数字,完全摆脱循环。

标签: c arrays algorithm


【解决方案1】:

使用forloops,尽量减少重复的代码

#include <stdio.h>

int main(void) {

    int lines, flag=1, val;

    for(lines=0;lines<3;lines++)
    {
            if(flag == 1)
                    for(val=1;val<=10;val++)
                            printf("%d ", val);
            else
                    for(val=10;val>0;val--)
                            printf("%d ", val);
            printf("\n");
            flag = -flag;
    }

    return 0;
}

【讨论】:

  • 这究竟是如何优化的?您所做的只是让代码更具可读性。
  • 每个打印值的比较少
【解决方案2】:

提示:您可以使用for 循环在任一方向进行迭代:

for (int i = 1; i <= 10; ++i)

for (int i = 10; i >= 1; --i)

此外,for 循环比while 更好,因为它确实向读者展示了“我正在从这个到那个迭代i。”

【讨论】:

    【解决方案3】:

    使用数组并在第一次迭代时正常迭代它,反之亦然在第二次迭代中,然后再次正常迭代。

    示例代码:

    #include <stdio.h>
    
    #define SIZE 10
    
    void print_arr(int* array, int size);
    void print_rev_arr(int* array, int size);
    
    int main(void)
    {
        int array[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int iter = 3;
    
        for(int i = 0; i < iter; ++i)
            if(i % 2)
                print_arr(array, SIZE);
            else
                print_rev_arr(array, SIZE);
        return 0;
    }
    
    void print_arr(int* array, int size)
    {
        for(int i = 0; i < size; ++i)
            printf("%d ", array[i]);
        printf("\n");
    }
    
    void print_rev_arr(int* array, int size)
    {
        for(int i = size - 1; i >= 0; --i)
            printf("%d ", array[i]);
        printf("\n");
    }
    

    输出:

    Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c 
    Georgioss-MacBook-Pro:~ gsamaras$ ./a.out 
    10 9 8 7 6 5 4 3 2 1 
    1 2 3 4 5 6 7 8 9 10 
    10 9 8 7 6 5 4 3 2 1 
    

    【讨论】:

      【解决方案4】:

      IO 完全解决了这个问题。

      但是向前迭代最快的方法是

      for(i=0;i<N;i++)
      

      最快最优雅的向后迭代方式是

      int i = N;
      while(N--)
      

      【讨论】:

      • 向后迭代最快、最优雅的方法是for(i=0;i&lt;N;i++)。然后使用something[N-i-1]
      • while(N--) 的问题在于,N 通常是一个常量,或者是传递给函数的参数,而其他代码依赖于该参数。脓,它取决于相当武断的(在我看来,是愚蠢的)约定,即 0 被认为是错误的,任何非零值都被认为是“非错误的”。
      • 我点点头。应该是while(i--)。
      【解决方案5】:

      你可以这样做:

      1. 使用从 1 开始到 10 的 for 循环。打印它的 计数器。
      2. 使用从 10 开始到 1 停止的 for 循环。打印它的 计数器。
      3. 使用从 1 开始到 10 的 for 循环。打印它的 计数器。

      示例代码:

      #include <stdio.h>
      
      #define LEN 10
      #define ITER 3
      
      int main(void)
      {
          for(int i = 0; i < ITER; ++i)
          {
              if(i % 2)
                  for(int j = 1; j <= LEN; ++j)
                      printf("%d ", j);
              else
                  for(int j = LEN; j >0; --j)
                      printf("%d ", j);
              printf("\n");
          }
          return 0;
      }
      

      输出:

      Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c 
      Georgioss-MacBook-Pro:~ gsamaras$ ./a.out 
      10 9 8 7 6 5 4 3 2 1 
      1 2 3 4 5 6 7 8 9 10 
      10 9 8 7 6 5 4 3 2 1 
      

      【讨论】:

        【解决方案6】:

        有两件事需要考虑。

        首先是程序是否最优。很容易证明你的程序是最优的(至少是渐近最优的)。您需要显示 3n 个数字,因此您至少需要 3n 次迭代。你有 3n 次迭代,所以没关系。您也许可以进一步优化迭代本身,但这将作为第二段的隐含结果出现。

        第二个是可读性。您的代码有点冗长且不灵活。考虑以下几点:

        int pattern[] = {1,2,3,4,5,6,7,8,9,10};
        int patternSize = sizeof(pattern)/sizeof(int);
        for (int i=0; i < 3; i++)
            for (int j=0; j<patternSize; j++) {
                if (i % 2)
                    printf("%d", pattern[patternSize - j - 1]);
                else
                    printf("%d", pattern[i])
            }
        

        代码更短更清晰。此外,它更易于维护。很清楚你必须做什么来改变模式。我可以将模式大小硬编码为 10,但是当您更改模式时,这将需要 2 次更改。我可以从 j 的值生成模式,但这会限制可以显示的模式数量。

        但是如果模式是从 1 到 200 的所有数字呢?当然我不会手写。只需用填充数组的 for 循环替换数组即可。您不必更改显示数组的代码。这是关注点分离的一个小例子——代码的一部分进行模式生成,另一部分进行显示,它们可以独立修改。

        虽然这是渐近最优的,但可以进行一些优化。例如,使用该数组存储模式不如从 j 生成模式高效。但在实践中,除非需要更高的效率,否则这种方法的优点超过了较小的性能损失。

        【讨论】:

        • 感谢您的深刻见解,我获得了很多好点。
        【解决方案7】:

        好的,这是我的看法,我认为它比大多数人更愉快:

        #include <stdio.h>
        
        int main(void)
        {
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 10; ++j)
                {
                    const int v = (i % 2) ? 10 - j : j + 1;
                    printf("%d ", v);
                }
                putchar('\n');
            }
            return 0;
        }
        

        几点:

        • 不使用数组,而是根据行号 (i) 和位置 (j) 生成非常简单的模式。
        • 不是为使用数组的“可插入”模式而设计的,因为该模式非常简单且重复,可用于简化代码。
        • 重复使用内部循环,而不是复制它。
        • 在适当的位置打印换行符,以实际获得单独的行(并非所有已发布的解决方案)。

        当然,通过将v 折叠到printf() 中,可以将内部循环的主体缩短为一行,但我的目标是提高可读性和清晰度。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-10-20
          • 2021-02-26
          • 1970-01-01
          • 1970-01-01
          • 2019-04-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多