我使用*
在特定的行和列中打印V。我有很多if
语句。我在下面分享我的代码
是否有任何优化的方式在10X10行列中打印V图案?(没有很多if
条件)?
#include <stdio.h>
int main() {
int row, column;
for (row = 1; row <= 10; row++) {
for (column = 1; column <= 10; column++) {
if (row == 1 && (column == 1 || column == 10)
|| row == 3 && (column == 2 || column == 9)
|| row == 5 && (column == 3 || column == 8)
|| row == 7 && (column == 4 || column == 7)
|| row == 10 && column == 5)
printf("*");
else
printf(" ");
}
printf("n");
}
return 0;
}
当您需要输出任意数量的空格时,一个合理的选择是使用printf
字符串宽度指定符左加空格:
printf("%*s*", spaces, "");
上面将输出空字符串,填充到整数值spaces
的宽度,然后输出*
。请注意,格式字符串%*s
意味着您既指定宽度,又指定字符串作为额外参数。该部分中的*
与实际的*
无关。我们将添加到格式字符串的末尾。
因此,对于V形,除了最后一行(如果宽度为奇数)外,每一行都有两个*
字符。直观地做到这一点的一种方法是跟踪每行V的左右部分的位置,然后进行数学计算以确定要添加多少填充。
的例子:
void v(int width)
{
int l = 0, r = width;
for (; l < r; l++, r--)
{
printf("%*s*%*sn", l, "", r-l, "*");
}
if (l == r)
printf("%*s*n", l, "");
}
如果您真的想要更精简的代码,您可以选择将最后一行滚动到循环中。在本例中,当l == r
时,您只想输出单个星号。否则你需要两个。因此,您可以输出字符串&"*"[l==r]
——这意味着当l==r
为真时,您将跳过星号,它将看起来像一个空字符串(因为您落在NUL终止符上)。
注意,这不是很好的风格。它牺牲可读性换取紧凑性。
void v(int width)
{
for (int l = 0, r = width; l <= r; l++, r--)
{
printf("%*s*%*sn", l, "", r-l, &"*"[l==r]);
}
}
所以,这是"有效率"在紧凑的代码和没有太多的函数调用方面。如果您关心的是printf
的格式解析,那么您可以完全避免它。下面,我们使用相同的左/右边界,并使用循环遍历每一行。这实际上做了我们的printf
在内部做的事情,除了更明显的是发生了什么:
void v(int width)
{
int l = 0, r = width-1;
for (; l <= r; l++, r--)
{
int x = 0;
for (; x < l; x++) putchar(' ');
putchar('*');
if (x < r)
{
for (x++; x < r; x++) putchar(' ');
putchar('*');
}
putchar('n');
}
}
现在来点好玩的…
作为练习,下面是printf
方法,但没有循环(使用递归):
void vv(int width, int row) {
if(width >= 0) {
printf("%*s*%*sn", row, "", width, &"*"[width==0]);
vv(width-2, row+1);
}
}
void v(int width) {
vv(width, 0);
}
这里是这个想法变成了一个看起来很酷的可怕的混乱。;)
#include <stdio.h>
#define VV int
#define vV "* %*s%*sn"
VV Vv( VV v ,VV
vv){if(v -->0){
printf (vV+2,
vv++ ,vV,v
,vV+ !v);
Vv(-- v,vv
);}} VV V
(VV v){
Vv(v,
1);
}
int main() {
for (int v = 1; v < 12; v++) {
printf("size %dn", v);
V(v);
}
}
我不认为这是优化的,但将更简单和可扩展的大小。
#include <stdio.h>
#define SIZE 10
#define MID ((SIZE-1)/2) // midst position of SIZE
#define ABS(x) ((x)<0?-(x):(x)) // absolute value of x
int main()
{
int i, j;
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
if (i % 2 == 0 && ABS(j - MID) == MID - i / 2) putchar('*');
else putchar(' ');
}
putchar('n');
}
return 0;
}
(解释)
假设SIZE
= 10,则计算出MID
的值为4。然后,v
形状的星号将被对称地放置在第四列。
让我们按照如下方式在列(j)和行(i)中放置数字:
012345678
* * 0 ABS(0 - 4) == 4 - 0, ABS(8 - 4) == 4 - 0
1 skipped as i & 2 != 0
* * 2 ABS(1 - 4) == 4 - 1, ABS(7 - 4) == 4 - 1
3 skipped
* * 4 ABS(2 - 4) == 4 - 2, ABS(6 - 4) == 4 - 2
5 skipped
* * 6 ABS(3 - 4) == 4 - 3, ABS(5 - 4) == 4 - 3
7 skipped
* 8 ABS(4 - 4) == 4 - 4
上面的方程式是加星号的条件。例如,在第0行中,我们想把它放在第0列和第8列。条件j - 4 == +/- 4
或ABS(j - 4) == 4
将表示由于对称性而产生的条件。如果我们把这个条件推广到行上,我们可以把它描述为i % 2 == 0 && ABS(j - MID) == MID - i / 2
.
这段代码考虑了行和*的位置之间的关系,如果您在第一行,那么我们希望第0列和第9列打印*,然后是第二行,我们希望第1列和第8列,以此类推。因此,我使用了行迭代器和列迭代器来知道在具体的行中打印的是哪一列。
#include <stdio.h>
int main()
{
int matrix_size = 10; //Assuming is squared matrix 10x10
int counter = 0;
int i,j;
for(i=0;i<(int)(matrix_size/2);i++) {
for(j=0;j<matrix_size;j++) {
if(j==i || j==(matrix_size-1-i)) {
printf("*");
}else{
printf(" ");
}
}
printf("n");
}
return 0;
}
编辑:与tshiono的解决方案相比,我只写了5行V,他打印了10行,但假设每行之间有一个空格行。这两种解决方案都是可以的,这取决于你想要什么。
对于对称的V形,行数和列数应该是奇数。下面是一个更简单的方法:
#include <stdio.h>
#include <stdlib.h>
int main() {
for (int n = 11, row = 0; row < n; row++) {
for (int column = 0; column < n; column++)
putchar(" *"[2 * abs(column - n / 2) == n - 1 - row]);
printf("n");
}
return 0;
}
输出:
* *
* *
* *
* *
* *
*
对于较粗的V形:
#include <stdio.h>
#include <stdlib.h>
int main() {
for (int n = 11, row = 0; row < n; row++) {
for (int column = 0; column < n; column++)
putchar(" *"[abs(2 * abs(column - n / 2) - (n - 1 - row)) <= 1]);
printf("n");
}
return 0;
}
输出:
* *
** **
* *
** **
* *
** **
* *
** **
* *
***
*
其他答案考虑到V的特定形状并围绕它进行优化。
对于任何形状,我都有一个优化的解决方案。
这涉及到一个查找表,其中包含构成该形状的*
字符的所有位置。
struct { int row,col; } shape[] = {
{1,1}, {1,10}, {3,2}, {3,9}, {5,3}, {5,8}, {7,4}, {7,7}, {10,5},
{-1,-1}
};
最后一个位置({-1,-1}
)与终止字符串的' '
的目的相同。