首页 > 其他分享 >创建菱形图案时的数学思维

创建菱形图案时的数学思维

时间:2024-08-23 18:51:40浏览次数:11  
标签:思维 填充 符号 图案 菱形 上半 line 空格

目录

前言

附:样例

1.1 固定生成5*5大小的菱形(最简单最基本的图形生成)

2.1 生成n*n大小的菱形(本质上缩小或增大了基本图形)

3.1 生成n*m大小的菱形(本质上在第二种变化基础上增加了角度变化)

一. 固定生成5*5基本大小的菱形(后文中称其为基础菱形)

1. 分析原理

1.1 代码逻辑

1.2 数学逻辑

1.3 逻辑实现

①菱形上半部分空格数

②菱形上半部分填充符号数

③菱形的下半部分空格数

④菱形下半部分的填充符号数

2.代码实现

二. 生成n*n大小的菱形(即对基础菱形放大或缩小)

1.分析原理

1.1 代码逻辑

1.2 数学逻辑

1.3 逻辑实现

①菱形上半部分空格数

 ②菱形上半部分填充符号数

③菱形的下半部分空格数

④菱形下半部分的填充符号数

2.代码实现

三. 生成n*m大小的菱形(即改变菱形的角度)

1.分析原理

1.1 代码逻辑

1.2 数学逻辑

1.3 逻辑实现

①菱形上半部分空格数

②菱形上半部分填充符号数

③菱形的下半部分空格数

④菱形下半部分的填充符号数

2.代码实现

 结言


前言

对于初学C语言的人而言,生成菱形一直都是需要跨过的一道坎,在这篇文章里,我将详细的讲解我对生成菱形的思路以及其背后的数学逻辑与方法,其中包括了固定大小菱形的生成到变大小菱形的生成到变角度菱形的生成,希望对看这篇文章的人都有所帮助。

附:样例

1.1 固定生成5*5大小的菱形(最简单最基本的图形生成)

2.1 生成n*n大小的菱形(本质上缩小或增大了基本图形)

3.1 生成n*m大小的菱形(本质上在第二种变化基础上增加了角度变化)

我们先从最简单的开始做起,以便进行生成复杂图形的推导

一. 固定生成5*5基本大小的菱形(后文中称其为基础菱形)

1. 分析原理

1.1 代码逻辑

我们可以通过观察发现菱形是由一个个空格与填充符号所构成的,那么我们只需要找出行数增加时的空格数与填充符号数增加的规律,并用for循环语句进行打印,就可以得到菱形。因此,我们需要设置行变量i,空格数变量j,填充符号数变量k。

1.2 数学逻辑

可以看到菱形上半部分的空格数是依次递减,而下半部分是依次递增,填充符号数则反之,其变化规律类似于分段函数,因此,在描述空格数与填充符号数的规律时,我们分菱形的上半部分和下半部分。

1.3 逻辑实现

①菱形上半部分空格数

通过观察,我们发现随着行数i的递增,上半部分菱形的空格数变化情况为:

行数(i)123
空格数210

观察得出规律:上半部分的空格数=3-i         ①
对应代码如下:

for (int j = 1; j <= 3 - i; j++) {//设置打印空格的循环次数,j表示空格行
    printf(" ");//打印空格
}
②菱形上半部分填充符号数

通过观察,我们发现随着行数i的递增,上半部分的填充符号数呈奇数列:

行数(i)123
填充符号数135

观察得出规律:上半部分的空格数=2*i-1         ②
对应代码如下: 

for (int k = 1; k <= 2 * i - 1; k++) {//设置打印符号的循环次数,k表示符号填充行
    printf("%c", ch);//打印符号
}
③菱形的下半部分空格数

通过观察,我们发现其空格数与行数减去3恰好相等:

行数(i)45
空格数12
即:下半部分空格数=i-3                                        ③  

 对应代码如下:

 for (int j = 1; j <= i - 3; j++) {
     printf(" ");//打印空格
 }

④菱形下半部分的填充符号数

通过观察,我们发现其填充符号数呈倒奇数列的形式,看到奇数列,依旧想到2n-1(n=1,2,3,......)的数学形式,在当前情况中,很显然n=i-3,但由于此时是倒奇数列,因此我们需要一个正偶数来减去奇数列来得到它,即4-(2*(i-3)-1)。 

行数(i)45
空格数31
化简得出结果: 下半部分的填充符号数=11-2*i     ④

 对应代码如下: 

for (int k = 1; k <= 11 - 2 * i; k++) {
    printf("%c", ch);
}
 

2.代码实现

总体代码如下:

void UtimateDiamond() {
    char ch = 0;//初始化变量,设置一个变量使其可以自由变换所用填充菱形的符号
    printf("\n请输入要填充图形的符号:");
    scanf("%c", &ch);//输入符号
    for (int i = 1; i <= 5; i++) {//i表示当前行数
        if (i <= 3) {//判断是否为菱形上半部分
            for (int j = 1; j <= 3 - i; j++) {//设置打印空格的循环次数,j表示空格行
                printf(" ");//打印空格
            }
            for (int k = 1; k <= 2 * i - 1; k++) {//设置打印符号的循环次数,k表示符号填充行
                printf("%c", ch);//打印符号
            }
        }
        else{//若i已经超过3,则说明此时为菱形下半部分
            for (int j = 1; j <= i - 3; j++) {
                printf(" ");//打印空格
            }
            for (int k = 1; k <= 11 - 2 * i; k++) {
                printf("%c", ch);
            }
        }
        printf("\n");//每一次循环结束换行,进行下一行的打印
    }
}

 现在逐级增加难度 

二. 生成n*n大小的菱形(即对基础菱形放大或缩小)

1.分析原理

1.1 代码逻辑

为了实现菱形的放大或缩小,很显然菱形的行数就成为了一个变量,由于此时菱形的行数和列数在变化中一直相等,因此,我们只需设置一个行数变量line。可知,当line=5时,此菱形为基础菱形,line增大时,即对基础菱形放大,line缩小时,即对基础菱形缩小【注意:line的最小值为可以生成的最小菱形的行数值,即line>=3,且line一定是奇数】。

1.2 数学逻辑

核心逻辑不变,为了确定当引入line变量后菱形上半部分和下半部分的分界线,我们需要对其公式进行推导,在纯数学领域上来说,上半部分的行数=line/2+0.5,但对C语言来说,由于line是int类型,2也是int类型,因此line/2也是int类型,其结果会丢失小数部分,所以再加0.5才能得到上半部分的行数,上半部分的行数=line/2+1。由于此时行数成为了一个变量,在必要时,我们可以画出多个line值情况下的菱形来找出行变量,空格数变量以及填充符号数变量的关系

1.3 逻辑实现

①菱形上半部分空格数

通过观察,我们发现随着行数i的递增,上半部分菱形的空格数变化情况为:

行数(i)123...line/2+1
空格数line/2line/2-1line/2-2...0

表格数据中的表达式并不是很容易直接想到,这时我们可以多画两个菱形示意图,分别按照基本菱形的方法列出上半部分的空格数的表达式去发现其中的规律,如下是 line=5 和 line = 7 以及 line = 3 时的菱形图像,其表达式按照基本菱形的方法得出的空格数表达式分别为:3-i ,  4-i , 2-i ,推断出上半部分的空格数为上半部分总行数减去当前行数i,即上半部分空格数=line/2+1-i。

line573
空格数表达式3 - i4 - i2 - i
line=3
line=5
line=7

       

观察得出规律:上半部分的空格数=line/2-i+1         ⑤
对应代码如下:

for (int j = 1; j <= line / 2 + 1 - i; j++) {//设置打印空格的循环次数,j表示空格行
    printf(" ");//打印空格
}
 ②菱形上半部分填充符号数

通过观察,我们发现随着行数i的递增,上半部分菱形的填充符号数变化情况为:

行数(i)123...line/2+1
填充符号数135...line

很显然,上半部分的填充数=2*i-1                            ⑥

对应代码如下:

for (int k = 1; k <= 2 * i - 1; k++) {//设置打印符号的循环次数,k表示符号填充行
    printf("%c", ch);//打印符号
}
③菱形的下半部分空格数

 依照上半部分空格数推导的经验来看,我们需要画出多个菱形示意图进行,分别参照基本菱形的方法找出相应的下半部分空格数表达式,老样子,还是使用line=3,line=5,line=7来举例,通过比较发现其下半部分空格数为当前行数减去菱形上半部分行数,即下半部分空格数 = i - (line / 2 + 1)

line\行数(i)34567
310000
5无效1200
7无效无效123

因此得出规律:下半部分的空格数 = i - line / 2 - 1   ⑦
对应代码如下:

for (int j = 1; j <= i - line / 2 - 1; j++) {//设置打印空格的循环次数,j表示空格行
    printf(" ");//打印空格
}
④菱形下半部分的填充符号数

 按照惯例,我们准备用找数字规律的方式进行公式推导式就比较吃力了,因为在使用基本菱形中的方法中,我们在确定正偶数时方法是通过为了得到倒奇数列的结果而进行的取值,这样的取值方式与我们的菱形没有多少关联,因此我们得从图像入手,寻找图像里更普适的规律。 

line=7

 这时我们注意到了菱形的对称性,既然菱形是对称的,那么其左右两边的空格数也应该相等,也就是说,只要知道了菱形一边的空格数,就能用总列数减去二倍当前行数的空格数,就能得到当前行的填充符号数,写成公式即:填充符号数=总列数-2*当前行的空格数,这个式子甚至适用于整个菱形,而不是一半的菱形,由于这个公式中的当前行空格数表达式已经被我们提前算出,因此这个式子也没有未知量。

 按照上述推导公式,我们的下半部分填充符号数=line-2*(i-line/2-1)。

最终化简得到,下半部分填充符号数=2*line-2*i+1     ⑧

对应代码如下: 

for (int k = 1; k <= 2 * line - 2 * i + 1; k++) {//设置打印符号的循环次数,k表示符号填充行
    printf("%c", ch);
}

2.代码实现

总体代码如下:

bool ZoomDiamond() {
    char ch = 0;//初始化变量,设置一个变量使其可以自由变换所用填充菱形的符号
    int line = 0;//初始化对角线长度
    printf("\n请输入要填充图形的符号:");
    scanf("%c", &ch);//输入符号
    printf("\n请输入你要的菱形的对角线长度(注意要大于2且只能是整奇数):");
    scanf("%d", &line);//输入对角线长度
    if (line < 3 || (line * 10) % 10 != 0 || line % 2 == 0) {//判断line是否大于3或者是否为整奇数
        printf("\n******非法输入******\n");
        return false;
    }
    for (int i = 1; i <= line; i++) {//i表示当前行数
        if (i <= line / 2 + 1) {//判断是否为菱形上半部分
            for (int j = 1; j <= line / 2 + 1 - i; j++) {//设置打印空格的循环次数,j表示空格行
                printf(" ");//打印空格
            }
            for (int k = 1; k <= 2 * i - 1; k++) {//设置打印符号的循环次数,k表示符号填充行
                printf("%c", ch);//打印符号
            }
        }
        else {//若i已经超过line/2+1,则说明此时为菱形下半部分
            for (int j = 1; j <= i - line / 2 - 1; j++) {//设置打印空格的循环次数,j表示空格行
                printf(" ");//打印空格
            }
            for (int k = 1; k <= 2 * line - 2 * i + 1; k++) {//设置打印符号的循环次数,k表示符号填充行
                printf("%c", ch);
            }
        }
        printf("\n");//每一次循环结束换行,进行下一行的打印
    }
    return true;
}

 终于到最终难度了

三. 生成n*m大小的菱形(即改变菱形的角度)

1.分析原理

1.1 代码逻辑

改变菱形的角度,也意味着菱形的行和列已经不相等了,因此我们设置两个变量line与column分别表示总行数和总列数【行和列均为奇数且大于3】。

1.2 数学逻辑

为了打开突破口,我们依旧需要先观察多个变化的菱形来找出它们之间的内在联系。使用控制变量法先将line定为5,变化column,得到以下几个图形:

图一
图二
图三
图四

column变化时各行的空格数

i12345
图一21012
图二42024
图三63036
图四84048

很显然,在column增加的过程中,菱形之间的空格增长数有倍数关系,菱形自身的每一行的空格增长有倍数关系,同时,column增长的过程中,为满足整个图形成菱形,不能以自增1的方式增加列数,因此,我们设置一个表示这个倍数的变量offset(在后文称做菱形的偏移量)。偏移量的大小代表了菱形中每到下一行时,减少的空格数的数目,其值一定大于0且为整数。例如对图一来说,偏移量为1,对图二来说,偏移量为2,对图三来说,偏移量为3。可以发现:偏移量越大,则菱形越扁,column越大,且如果说图一为基本菱形,那么图二,图三,图四与基本菱形的相应行的空格数是其本身菱形的偏移量倍,由此我们在n*n菱形的基础上加入offset变量进行公式变形从而获得其菱形的空格数。

1.3 逻辑实现

①菱形上半部分空格数

按照上面数学逻辑的推论,我们可以直接对公式⑤进行变形,加入offset量后,可以得到菱形上半部分的空格数=offset*(line/2+1-i)。

化简后得到,上半部分空格数=offest*line/2+offest-offest*i            ⑨

[补充:还记的上面写的column不能随意增加的事吗?它与offest有关系,观察菱形可以得知,第一行空格数*2+1=总列数,因此column=offset*(line-1)+1,所以在输入参数时,我们只需要输入line与offest即可]

其对应代码为:

for (int j = 1; j <= (offest * line / 2 + offest - offest * i); j++) {//设置打印空格的循环次数,j表示空格行
    printf(" ");//打印空格
}
②菱形上半部分填充符号数

这里的菱形显然不满足连续的奇数列了,这时我们要想到之前我们所推导出来的填充符号数=总列数-2*当前行的空格数,由此,我们可以得到菱形上半部分的填充符号数=column-2*(offset*(line/2+1-i))。

化简后得到,上半部分的填充符号数=column-offest*line+2*offest*i-offest      ⑩

其对应代码为:

for (int j = 1; j <= (offest * i - line / 2 * offest - offest + offest / 2); j++) {//设置打印空格的循环次数,j表示空格行
    printf(" ");//打印空格
}
③菱形的下半部分空格数

与上半部分的空格数推导过程相似,下半部分的空格数目也满足基本菱形的偏移量倍,对⑦式变形可知,下半部分的空格数=offest*(i - (line / 2 + 1))。

化简可知:下半部分的空格数=offest*i-line/2*offest-offest+offest/2【注意这里不能将offset合并同类项,否则会出现问题】

其对应代码为:

for (int j = 1; j <= (offest * i - line / 2 * offest - offest + offest / 2); j++) {//设置打印空格的循环次数,j表示空格行
    printf(" ");//打印空格
}
④菱形下半部分的填充符号数

同样使用填充符号数=总列数-2*当前行的空格数,可知:下半部分的填充数=column-2*offest*(i - (line / 2 + 1))。

化简可得:下半部分的填充数=column-2*i*offest+offest*line+offest

其对应代码为:

for (int k = 1; k <= (column - 2 * i * offest + offest * line + offest); k++) {//设置打印符号的循环次数,k表示符号填充行
    printf("%c", ch);
}  

2.代码实现

总体代码如下:

bool NormalDiamond() {
    char ch = 0;//初始化变量,设置一个变量使其可以自由变换所用填充菱形的符号
    int line = 0, column = 0;//初始化行数和列数
    int offest = 0;//初始化菱形的偏移量
    printf("\n请输入要填充图形的符号:");
    scanf("%c", &ch);//输入符号
    printf("\n请输入你要的菱形的行数(注意要大于2且只能是整奇数):");
    scanf("%d", &line);//输入行数
    if (line < 3 || (line * 10) % 10 != 0 || line % 2 == 0) {//判断line是否大于3或者是否为整奇数
        printf("\n******非法输入******\n");
        return false;
    }
    printf("\n请输入你要的菱形的偏移量(注意要大于0且只能是整数):");
    scanf("%d", &offest);//输入菱形偏移量
    if (offest < 1 || (offest * 10) % 10 != 0) {//判断offest是否为整数且大于1
        printf("\n******非法输入******\n");
        return false;
    }
    column = offest * line - offest + 1;//计算在当前条件下的列数
    for (int i = 1; i <= line; i++) {//i表示当前行数
        if (i <= line / 2 + 1) {//判断是否为菱形上半部分
            for (int j = 1; j <= (offest * line / 2 + offest - offest * i); j++) {//设置打印空格的循环次数,j表示空格行
                printf(" ");//打印空格
            }
            for (int k = 1; k <= (column - offest * line + 2 * offest * i - offest); k++) {//设置打印符号的循环次数,k表示符号填充行
                printf("%c", ch);//打印符号
            }
        }
        else {//若i已经超过line/2+1,则说明此时为菱形下半部分
            for (int j = 1; j <= (offest * i - line / 2 * offest - offest + offest / 2); j++) {//设置打印空格的循环次数,j表示空格行
                printf(" ");//打印空格
            }
            for (int k = 1; k <= (column - 2 * i * offest + offest * line + offest); k++) {//设置打印符号的循环次数,k表示符号填充行
                printf("%c", ch);
            }       
        }
        printf("\n");//每一次循环结束换行,进行下一行的打印
    }
    return true;
}

 结言

       第一次在上面发表技术文章,我兴奋的打了差不多一天的字,好累ㅠ ㅅ ㅠ,但是写完之后又是满满的成就感。

       如果你看完了这篇文章,你可能有所疑惑,为什么不一开始就用最好的结论,而非要去找规律,其实我的想法是,思路和技巧都是慢慢积累的,最开始的时候谁也不知道有这么简单的结论,我就想着把自己的思考过程展示给大家,由简入繁,我们学习任何一个东西都不可能一蹴而就,我们大多数的人,最初的学习都是从显而易见的道理开始,然后逐渐熟悉后在此基础上领悟出新的道理。这也是我写这篇文章想要表达的事情。漫漫人生路,何尝也不是如此呢?

       最后,诚邀大家对我的文章斧正或改进,感激不尽。

标签:思维,填充,符号,图案,菱形,上半,line,空格
From: https://blog.csdn.net/2301_80201235/article/details/141445024

相关文章

  • AtCoder Beginner Contest 中的小思维题
    078Dhttps://atcoder.jp/contests/abc078/tasks/arc085_b问题陈述我们有一副由\(N\)张牌组成的扑克牌。每张牌上都写着一个整数。从最上面开始的第\(i\)张牌上的整数是\(a_i\)。两个人X和Y将用这副扑克牌玩一个游戏。最初,X手中有一张写有\(Z\)的牌,Y手中有一张......
  • 做思维导图?chatmoney轻轻松松拿下
    本文由ChatMoney团队出品嘿,各位职场朋友们是不是常常对着密密麻麻的笔记感到焦虑呢?想整理却无从下手?别怕,ChatmoneyAI知识库来拯救你的整理困难症啦!咱们都知道,思维导图是职场中必备的神器它能帮我们理清思路,记忆知识但传统做法嘛,不是画得乱七八糟就是费时费力,真心不方便......
  • 听劝❗用AI做职场思维导图仅仅需要几秒钟啊
    本文由ChatMoney团队出品嘿,各位职场朋友们是不是常常对着密密麻麻的笔记感到焦虑呢?想整理却无从下手?别怕,ChatmoneyAI知识库来拯救你的整理困难症啦!咱们都知道,思维导图是职场中必备的神器它能帮我们理清思路,记忆知识但传统做法嘛,不是画得乱七八糟就是费时费力,真心不方便......
  • 【教学类-72-02】20240819建筑对称图纸02(图案最大化)
    背景需求【教学类-72-01】20240803建筑对称图纸01-CSDN博客文章浏览阅读423次,点赞13次,收藏5次。【教学类-72-01】20240803建筑对称图纸01https://blog.csdn.net/reasonsummer/article/details/140893003我感觉房子有大有小,有大量空白,我想让建筑变得最大使用以下代码,把房子......
  • 【教学类-76-01】20240820书包01(图案最大化)
    背景需求通义万相生成图片,把图案最大化的方法(切掉白边)【教学类-75-01】20240817“通义万相图片最大化+透明png”的修图流程-CSDN博客文章浏览阅读1.6k次,点赞56次,收藏17次。【教学类-75-01】20240817“通义万相图片最大化+透明png”的修图流程https://blog.csdn.net/reasons......
  • 【转】管理者,一定要有道-法-术的思维模型
    我有一个观点:作为管理者,必须要有“道法术”的思维模型。具备这样的思维,才能穿透表象,站在更高的维度去解决管理上遇到的问题。今天,我们一起来聊聊这个话题。 术:学工具、学方法问题来了,什么是术?王东岳老师说:术,就是看你能驱动什么。简单来说,术,就是工具,就是你掌握的方法,......
  • 题解:Codeforces Round 967 (Div. 2) B [思维/构造]
    B.GeneratePermutationtimelimitpertest:1.5secondsmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputThereisanintegersequence\(a\)oflength\(n\),whereeachelementisinitially\(-1\).Misukihastwoty......
  • 利用java设计模式的思维优化代码
    在Java开发中,设计模式提供了一套解决常见软件设计问题的成熟方案。通过合理应用设计模式,可以提高代码的可维护性、可读性和扩展性。以下是几个常用设计模式的示例,说明如何利用设计模式思维来优化代码。1.工厂模式(FactoryPattern)场景:假设你在开发一个系统,需要创建不同类......
  • 一款专为内网办公环境设计的操作系统,集成了Word、Excel、PPT、PDF编辑器,内网聊天、白
    前言在当今数字化办公时代,企业面临着多样化的办公需求。现有软件往往存在一些痛点,如操作复杂、兼容性差、资源消耗高,以及在内网环境下的通讯和文件共享不便。这些限制不仅影响了工作效率,也制约了企业的数字化转型。因此,一款能够处理这些问题的软件显得尤为迫切。介绍GodoOS......
  • TCP 通信-Qt-思维导图-学习笔记
    TCP通信TCP简介TCP协议概述全称:TransmissionControlProtocol(传输控制协议)特性:面向连接、可靠、基于字节流的传输层通信协议TCP通信流程建立连接:TCP通信必须先建立连接通信端:分为客户端和服务端服务端操作监听端口:服务端监听某个端口,等待客户端连接......