【C语言】for循环打印菱形、心形个人思路步骤+心得

(2022/01/13更新 新版解法)

注:本人CS系大学生。C之前有接触过但基本忘得差不多了,目前在重新学习C。

今天看到个题目,说是用C的for循环语句打印一个图示的实心菱形:

对别人来说很简单,但对于我这个刚刚认识完循环语句的新手来说很难。光是想就想了很久很久,终于想出来了。写这篇博客一是将自己的思路存档供日后查看,二是把我的思路分享给大家,希望对同样是学习路上的大家有所帮助。完整源码在文末。

题目要求打印的效果是菱形,但实际上我们可以构造一个7*7的正方形。只不过菱形的组成部分用星号来表示,而空白部分则用表示。这里以一个7*7的菱形为例:

空白效果:

实际效果:

第一步思路就清晰地出来了,使用两个for语句来生成空白的正方形:

#include<stdio.h>
int main() {
	int coloum = 7; // 定义菱形的宽(高)度
	// i代表行, j代表列
	for (int i = 0;i <= coloum;i++) {
		for (int j = 0;j <= coloum;j++) {

		}
	}
}

之后我们先让它们生成只有空格的7x7的正方形。为了方便识别,这里空格用"?"代替。

#include<stdio.h>
int main() {
	int coloum = 7; // 定义菱形的宽(高)度
	// i代表行, j代表列
	for (int i = 0;i <= coloum;i++) {
		printf("? ");
		for (int j = 0;j <= coloum;j++) {
			printf("? ");

		}
		printf("\n"); // 别忘了换行噢
	}
}

生成的效果如下:

成功生成正方形之后,接下来思考如何在这个正方形之中来画出所需要的实心菱形。

再来观察一下应该得到的图形的样子:

想要在这个正方形内画出菱形,就要确认组成菱形的每一个星号所在的位置。

你会发现每一行至少都会有一个星号,而且最中间的列一定会有一个星号。 那么其余的星号也一定与这个中间列的星号有关。我们将这个中间列的星号定义为int mid = coloum/2+1,即中位数。

只要找到了星号位置的变化规律,代码的思路就出来了。

(注意:在C中对整数进行除运算时会向下取整。想要获得之中位数的话,需要在原来的值上+1)

从第4行看起,第1、第2、第3、第4行的星号数量都是呈金字塔状递增的;而第5、第6、第7行的星号数量呈金字塔状递减。那么说明在不同行之间,星号的变化规律并不完全一样。所以我们需要把行数分割为上半部分和下半部分,也就是说,我们要对i的取值分别讨论。

#include<stdio.h>
int main() {
	int coloum = 7; // 定义菱形的宽(高)度
	int mid = coloum / 2 + 1; // 获取菱形行(列)的中位数,也就是最中间行(或列)的位置
	// i代表行, j代表列
	for (int i = 0;i <= coloum;i++) {
		if (i <= mid) { // 当行数处于上半区(包括最中间的行)时
			for (int j = 0;j <= coloum;j++) {
				printf("? ");
			}

		}else if (i > mid) { // 当行数处于下半区时
			for (int j = 0;j <= coloum;j++) {
				printf("? ");
			}
		
		}
		printf("\n"); // 别忘了换行噢
	}
}

我们将上半区单独分出来仔细观察:

在第一行中,星星所处的位置只有4。

在第二行中,星星所处的位置为3,4,5。即[3,5]这个区间。

在第三行中,星星所处的位置为2,3,4,5,6。即[2,6]这个区间。

在第四行中,星星所处的位置为1,2,3,4,5,6,7。即[1,7]这个区间。

不难发现,星星所处的位置为一个闭区间,分别为[4,4],[3,5],[2,6],[1,7]……即为4±0,4±1,4±2……

所以我们可以这样想:如果j(列数)处于这个区间内,那么输出“*”,否则输出空格。而且这些区间都是与菱形宽(高)度的中位数相关的。

即,星号的位置为一个区间。而对于上半区来说,这个区间为:[行的中位数(mid)-(当前行数-1),行的中位数(mid)+(当前行数-1)]。用代码实现便是:

for (int j = 1;j <= coloum;j++) {
				if (j >= mid - (i - 1) && j <= mid + (i - 1)) {
					printf("*");
				}
				else
					printf(" ");
			}

执行结果如下:

(因为还没处理下半部分代码,所以那里全是问号) 

接下来我们来看下半区:

 在第五行中,星号所处的位置为2,3,4,5,6,即[2,6]这个区间。

在第六行中,星号所处的位置为3,4,5,即[3,5]这个区间。

在第七行中,星号所处的位置只有4。

不难发现,星号所处的位置为一个闭区间,分别为[2,6],[3,5],[4,4]。即为4±2,4±1,4±0。星号的变化顺序刚好与前3行相反,为递减关系。

对于下半区来说,星号所处的区间规律为:[mid-(总行数-当前行数),mid+(总行数-当前行数)]。用代码实现就是:

for (int j = 1;j <= coloum;j++) {
				if (j >= mid - (coloum - i) && j <= mid + (coloum - i)) {
					printf("*");
				}
				else
					printf(" ");
			}

执行结果如下:

至此,代码已完成,可以实现题目要求的功能。可以自由改动column的值,生成任意大小的菱形。(注:coloum值必须为奇数,不然不能生成菱形) 

打印实心菱形的完整源码如下:

#include<stdio.h>
int main() {
	int column = 7; // 定义菱形的高度(宽度)
	int mid = column / 2 + 1; // 获取菱形高(宽)的中位数
	printf("%d\n", mid);
	// i是行数 j是列数
	for (int i = 1;i <= column;i++) { // 对行进行循环
		if (i <= mid) { // 判断行数是在上方还是下方。这里是上方的情况(包括中间一行
			for (int j = 1;j <= column;j++) { // 对列进行循环
				// 判断单个列的情况
				// 对上半区来说:
				// 星星的位置为一个区间 即[行的中位数-(行数-1),行的中位数+(行数-1)]
				if (j >= mid - (i - 1) && j <= mid + (i - 1)) {  
					printf("*"); // 输出星号
				}
				else
					printf(" "); // 输出空格
			}
		}
		else if (i > mid) { // 判断行数是否处于下方
			for (int j = 1;j <= column;j++) {
				// 判断单个列的情况
				// 对下半区来说:
				// 星星的位置为一个区间 即[行的中位数-(总行数-当前行数),行的中位数+(总行数-当前行数)]
				if (j>=mid-(column-i) && j<=mid+(column-i)) {  
					printf("*"); // 输出星号
				}
				else
					printf(" "); // 输出空格
			}

		}
		printf("\n");
	}
}

那么,通过上文的思路,打印空心菱形也不难。我们只需将j的判断语句改为等于最左边或最右边星号的位置即可。

打印空心菱形的完整源码如下:

#include<stdio.h>
int main() {
	int coloum = 7; // 定义菱形的宽(高)度
	int mid = coloum / 2 + 1; // 获取菱形行(列)的中位数,也就是最中间行(或列)的位置
	// i代表行, j代表列
	for (int i = 1;i <= coloum;i++) {
		if (i <= mid) { // 当行数处于上半区(包括最中间的行)时
			for (int j = 1;j <= coloum;j++) { 
				if (j == mid - (i - 1) || j == mid + (i - 1)) {  // 将判断条件改为最左边的星号和最右边的星号即可
					printf("*");
				}
				else
					printf(" ");
			}

		}else if (i > mid) { // 当行数处于下半区时
			for (int j = 1;j <= coloum;j++) {
				if (j == mid - (coloum - i) || j == mid + (coloum - i)) {  // 将判断条件改为最左边的星号和最右边的星号即可
					printf("*");
				}
				else
					printf(" ");
			}
		
		}
		printf("\n"); // 别忘了换行噢
	}
}

执行结果如下:

而如果需要打印实心心形的话,我们不妨借助上文的思路,通过上文的拆分来将心形拆分为上半部分和下半部分:

 将图形往上移:

心形的结构比菱形稍微复杂一点,要多画几个心形来观察:

 我们只需观察心形的上半部分(注:不包含最中间的那行)即可。来仔细观察上半部分:

仔细思考星号位置出现的规律,可以发现上半部分星号的位置属于这个区间:

[mid-当前行,当前行] ∪ [mid+mid-当前行,mid+当前行]

这个区间一样适用于没有任何星号的前几行。

那么,完整代码实现如下:

#include<stdio.h>
int main() {
	int coloum = 11; // 定义心形的高度。必须为奇数
	int mid = coloum / 2 +1; // 获取心形列数的中位数,也就是最中间列的位置。
	// i代表行, j代表列
	for (int i = 1;i <= coloum;i++) { 
		if (i < mid) { // 当行数处于上半区(不包括中间的行)时
			for (int j = 1;j <= coloum;j++) {  
				if (( j>=mid-i && j<=i) || (j>=mid+mid-i && j<=mid+i )) {  // 当星号处于 [mid-当前行,当前行] ∪ [mid+mid-当前行,mid+当前行] 区间时
					printf("*");
				}
				else
					printf(" ");
			}

		}else if (i >= mid) { // 当行数处于下半区(包括中间的行)时
			for (int j = 1;j <= coloum;j++) { 
				if (j >= mid - (coloum - i) && j <= mid + (coloum - i)) {  // 正常菱形下半区
					printf("*");
				}
				else
					printf(" ");
			}
		
		}
		printf("\n"); // 别忘了换行噢
	}
}

执行结果如下:

在网上搜了一下,没有具体的这种找规律然后用循环语句写出来的心形。心形上半区的规律真的很难找出来,我自认为我写得还是比较粗糙的。如果有大神有更好的思路的话,一定要不吝赐教!

总结:写代码一定要自己动手,多思考。动手和思考是最重要的,不要随随便便地就用百度找答案,多思考可以锻炼自己的思维,对日后的写代码都很有帮助。

2022/1/13:

今天看到有个视频有了更好的解法,不用分上下部分,也不用我这么复杂的判断。贴思路分享给大家:

这个图形在控制台输入时只由空格星号组成,且是先打印空格,再打印星号。因此我们只要找出打印空格和星号的规律即可

先初始化代码,写出大体的框架: 

int column = 7; // 定义菱形的宽度
	int mid = column / 2 + 1; // 定义中位数
	int i, j; // i是行, j是列
	for (i = 1;i <= column;i++) {
		for (j = 1;j <= exep1;j++) { // exep1为空格列的判断语句

		}
		for (j = 1;j <= exep2;j++) { // exep2为星号列的判断语句

		}
	}

其中exep1、exep2分别为j处于空格列、星号列的判断语句。当语句满足对应的条件时,就输出空格或星号。因为菱形左边必定输出空格,剩余部分必定输入星号,因此需要两个j的for循环依次执行。

动手列个表,观察每一行空格、星号的个数规律:

 

发现空格的数量是|行数的中位数 - 行数|,星号的数量是(总行数-|中-行|*2。那么完整代码实现如下:

int column = 7; // 定义菱形的宽度
	int mid = column / 2 +1; // 定义中位数
	int i, j; // i是行, j是列
	for (i = 1;i <= column;i++) {
		for (j = 1;j <= abs(mid-i);j++) { // exep1为空格列的判断语句
			printf(" ");
		}
		for (j = 1;j <= column-abs(mid-i)*2;j++) { // exep2为星号列的判断语句
			printf("*");
		}
		printf("\n");
	}

输出与上方菱形一致。

同理,想要用这个方法打印空心菱形的话,只需把星号列的判断条件改为“==”并加上j==1即可。

int column = 7; // 定义菱形的宽度
	int mid = column / 2 +1; // 定义中位数
	int i, j; // i是行, j是列
	for (i = 1;i <= column;i++) {
		for (j = 1;j <= abs(mid-i);j++) { 
			printf(" ");
		}
		for (j = 1;j <= column;j++) { 
			if (j == 1 || j == column - abs(mid - i) * 2) {
				printf("*");
			}
			else {
				printf(" ");
			}
		}
		printf("\n");
	}

 

  • 59
    点赞
  • 203
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值