这道题目要求我们使用C++编程语言输出一个特定规律的"日"字形矩阵。作为一名有多年编程经验的开发者,我发现这类图形输出题目在编程竞赛和算法练习中非常常见,能够很好地考察编程基础能力。
题目要求我们根据输入的整数n,输出一个n×n的矩阵,这个矩阵需要满足以下条件:
这样组合起来,整个矩阵就会呈现出一个"日"字的形状。比如当n=5时,输出应该是:
code复制|--|
-x-x-
|--|
-x-x-
|--|
解决这个问题的关键在于如何正确地使用循环结构和条件判断来控制每个位置的输出。我们需要:
让我们先来看一下完整的代码实现:
cpp复制#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for(int i = 1; i <= n; i++) { // 控制行数
for(int j = 1; j <= n; j++) { // 控制列数
if(j == 1 || j == n) { // 第一列或最后一列
cout << '|';
}
else if(i == 1 || i == n || i == (n + 1) / 2) { // 第一行、最后一行或中间行
cout << '-';
}
else { // 其他位置
cout << 'x';
}
}
cout << endl; // 每行结束后换行
}
return 0;
}
输入处理部分:
cpp复制int n;
cin >> n;
这里我们声明一个整型变量n,并从标准输入读取它的值。这个n代表矩阵的行数和列数(因为是正方形矩阵)。
外层循环:
cpp复制for(int i = 1; i <= n; i++)
这个循环控制矩阵的行数,i从1到n,表示当前正在处理第i行。
内层循环:
cpp复制for(int j = 1; j <= n; j++)
这个循环控制矩阵的列数,j从1到n,表示当前正在处理第j列。
条件判断部分:
cpp复制if(j == 1 || j == n)
这个条件判断当前位置是否在第一列或最后一列,如果是,则输出'|'。
cpp复制else if(i == 1 || i == n || i == (n + 1) / 2)
如果不是第一列或最后一列,则判断是否在第一行、最后一行或中间行。这里(n + 1) / 2是计算中间行号的技巧,利用了整数除法的特性。
默认情况:
cpp复制else {
cout << 'x';
}
如果以上条件都不满足,则输出'x'。
换行处理:
cpp复制cout << endl;
每处理完一行后,输出换行符,确保下一行字符从新的一行开始输出。
计算中间行时使用了(n + 1) / 2这个表达式,这是一个非常实用的技巧:
这种写法比使用浮点数运算后再取整更高效,也更符合C++的整数运算特性。
在实际编程中,我们需要特别注意边界条件的处理:
n的取值范围:题目虽然没有明确说明n的范围,但通常这类题目中n至少为3,否则无法形成有效的"日"字形。在实际应用中,可以添加输入验证:
cpp复制if(n < 3) {
cout << "n must be at least 3" << endl;
return 1;
}
行列编号的选择:代码中使用了从1开始的索引(i和j从1到n),这比从0开始更直观,减少了出错的可能性。
虽然这个问题规模很小,不需要考虑性能优化,但养成良好的编程习惯很重要:
减少重复计算:可以把(n + 1) / 2提前计算并存储,避免在每次循环中都重新计算:
cpp复制int mid = (n + 1) / 2;
使用putchar代替cout:对于简单的字符输出,putchar比cout更高效:
cpp复制putchar('|');
问题现象:输出的图形不像"日"字,或者某些位置的字符不正确。
可能原因及解决方案:
(n + 1) / 2是否正确问题现象:所有字符都输出在一行上。
解决方案:确保在内层循环结束后输出endl或\n。
问题现象:程序无法正确处理输入或陷入死循环。
解决方案:
cpp复制if(!(cin >> n)) {
cout << "Invalid input" << endl;
return 1;
}
我们可以扩展程序,支持不同粗细的"日"字。例如,让用户指定边框的宽度:
cpp复制int borderWidth;
cin >> borderWidth;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(j <= borderWidth || j > n - borderWidth) {
cout << '|';
}
else if(i <= borderWidth || i > n - borderWidth ||
(i >= (n + 1) / 2 - borderWidth / 2 &&
i <= (n + 1) / 2 + borderWidth / 2)) {
cout << '-';
}
else {
cout << 'x';
}
}
cout << endl;
}
为了提高代码的可读性和复用性,我们可以将核心逻辑封装成函数:
cpp复制void printRiMatrix(int n) {
int mid = (n + 1) / 2;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(j == 1 || j == n) {
cout << '|';
}
else if(i == 1 || i == n || i == mid) {
cout << '-';
}
else {
cout << 'x';
}
}
cout << endl;
}
}
int main() {
int n;
cin >> n;
printRiMatrix(n);
return 0;
}
我们可以让用户自定义使用的字符:
cpp复制char vertical, horizontal, fill;
cin >> vertical >> horizontal >> fill;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(j == 1 || j == n) {
cout << vertical;
}
else if(i == 1 || i == n || i == (n + 1) / 2) {
cout << horizontal;
}
else {
cout << fill;
}
}
cout << endl;
}
虽然这个问题规模很小,但分析算法复杂度是良好的编程习惯:
对于n≤1000的规模(这在编程竞赛中很常见),这个算法效率完全足够。
为了验证程序的正确性,我们应该设计多种测试用例:
最小情况:n=3
code复制|-|
|-|
|-|
奇数情况:n=5
code复制|--|
-x-x-
|--|
-x-x-
|--|
偶数情况:n=6
code复制|----|
-x--x-
-x--x-
|----|
-x--x-
-x--x-
较大数值:n=9,验证程序是否能正确处理更大的矩阵
边界情况:n=1(虽然题目可能不要求支持,但测试程序如何处理)
这类图形输出问题虽然简单,但它体现了编程中的几个重要概念:
在实际开发中,类似的思路可以应用于:
掌握了这些基础后,可以进一步学习更复杂的图形算法,如: