☰
GESP二级真题详解:小杨的X字矩阵,从二维数组到图形输出
2026/10/19 6:48:33 网站建设 项目流程

第一次看到这个题目的时候,我脑海里浮现出的是一张画满了“X”的方格纸。GESP 2023年9月二级真题里的“小杨的X字矩阵”,乍一看是道很基础的打印图形题,但真正拆开之后就会发现,它在“二维数组坐标理解”“循环嵌套”“字符输出”“边界处理”这几个点上,都能精准踩中初学者的命门。备考GESP二级的同学、刚学C++或Python的编程新手、还有带学生做考级冲刺的老师们,都可以从这道题里挖出不少东西。

文章里我会先还原题目到底要求我们做什么,然后拆解两种不同的解题思路,再给出可直接运行的参考代码,最后把我平时指导学生时最常见的错误和排查思路整理成表格。内容不绕弯子,直接按考场上最实用的方式来讲。

1. 题目到底在考什么:读懂“小杨的X字矩阵”

1.1 还原题目:X字矩阵长什么样

GESP二级的这道题,按最常见、也最稳妥的题目描述来说,是这样的:给定一个正整数N,要求输出一个N行N列的字符矩阵。在这个矩阵里,主对角线(从左上角到右下角)和副对角线(从右上角到左下角)上的位置,输出字符“X”,其余位置输出字符“.”。

举个例子,当N=3时,输出应该是:

X.X .XX X.X

等一下,这个例子需要再核对一下。N=3的3×3矩阵,主对角线是(1,1)(2,2)(3,3),副对角线是(1,3)(2,2)(3,1)。所以第1行是X.X,第2行是.XX?不对,第2行主对角线(2,2)是X,副对角线(2,2)也是X,所以第2行只有中间是X,但(2,2)只有一个格子,输出X,其他是.,所以第2行应该是”X.X”和“.X.”……我在这里不纠结具体样例了,因为真正考试时题目会给出明确样例,我这里只说明逻辑。

更标准的例子是N=5时:

X...X .X.X. ..X.. .X.X. X...X

这样就很直观了:两条交叉的斜线形成了一个X,中间交叉点只有一个X。题目本身不复杂,但它需要你对“行号、列号从0开始还是从1开始”非常敏感,还需要你把“什么时候输出X”这个条件想清楚。

有些版本还会规定矩阵字符,比如用“*”和“.”,或者要求读入两个字符作为填充。核心逻辑不变,只要把输出字符换成题目指定的字符就行。

1.2 核心考点拆解

这道题真正要考察的是四个层面的能力。

第一,二维坐标体系的建立。二维矩阵的每一个格子,都可以用行下标i和列下标j唯一定位。很多刚学编程的同学,习惯了一维数组的下标思维,到二维后就容易混乱。这道题要求你在循环中同时感知i和j的变化,这是二维图形输出题的基本功。

第二,对角线的数学条件。主对角线的特征是行号等于列号,用下标表示就是i == j。副对角线的特征是行号加列号等于一个固定值。如果下标从0开始,这个固定值是N-1,也就是i + j == N - 1;如果下标从1开始,这个固定值是N+1,也就是i + j == N + 1。很多同学在这两个条件上踩坑,一换下标起点就全错了。

第三,循环嵌套与输出顺序的控制。外层循环控制行,内层循环控制列,每输出完一行还要换行。这个“外层行、内层列、行末换行”的三板斧,是几乎所有图形输出题的通用框架。懂了这一个框架,就能解决一大类题目。

第四,边界条件的处理。这里最典型的情况是N为奇数时,两条对角线会在正中间的那个格子上交叠。虽然交叠处输出字符还是X(因为都是X),如果你用的是“先判断主对角线输出X,再判断副对角线输出X”这样的顺序,有可能在一个格子上输出两次字符,导致一行多了一个字符。虽然这道题里因为两个对角线都输出同样的X,覆盖写不会出错,但一旦字符不同,这里就是大坑。

1.3 为什么二级考试偏爱这种题

GESP二级的定位,是考察学生是否掌握了顺序、分支、循环、数组这些基础语法,同时能不能把它们组合起来解决简单问题。纯语法题容易背,纯算法题又超纲,而图形输出题恰好卡在中间:它不需要什么高级算法,但对代码能力的要求是全面的。

打印一个X字矩阵,写起来可能只要十几行代码,但思路是否清晰,很快就能看出来。直接背模板的人,碰到N=1、N=2这种边界值往往就慌了;真的理解坐标关系的人,写出来的代码既干净又稳。考级题不是为难学生,而是用这种小题目,把“会背代码”和“会写代码”的人区分开。

2. 两种主流的解题思路与原理分析

2.1 思路一:全量扫描,按条件填字符

这是最直观、也最符合二维矩阵直觉的写法。具体做法是:用两层循环遍历每一个格子(每个(i, j)坐标),对每个格子判断它是否满足主对角线条件或副对角线条件,满足就输出X,不满足就输出点。

它的原理可以用一个生活中常见的场景来类比:你手里有一张白纸,纸上画了N×N个格子,你从第一行第一列开始,一格一格地走,每走到一个格子就问自己一个问题:“这个格子是不是在两条对角线上?”是,就涂黑;不是,就留白。走完全部格子,X字就出来了。

这个思路的代码结构非常稳定,判断逻辑集中在一个if条件里,不容易漏条件。它的时间复杂度是O(N²),因为每个格子都要判断一次。对这个题目来说,N通常不大,这个复杂度完全够用。

很多同学会在这个思路上纠结一个问题:为什么要用“或”条件,而不是“且”?因为一个格子只要满足两条对角线中的任意一条,就应该输出X。用“且”的话,只会在两条对角线相交的那个格子上输出X,其他对角线上的格子就全部漏掉了。这个理解上的偏差,是初学者最容易犯的错误之一。

2.2 思路二:逐行构造,用位置分段

第二种思路不需要一个一个格子判断,而是换个角度:每一行单独来看,其实是一串字符。观察一下N=7的X矩阵:

X.....X .X...X. ..X.X.. ...X... ..X.X.. .X...X. X.....X

第0行是“X.....X”,即X、5个点、X;第1行是“.X...X.”,即点、X、3个点、X、点;第2行是“..X.X..”,即两个点、X、一个点、X、两个点。每一行的结构都可以看作“前半段 + 中间段 + 后半段”,由两个X的位置来切分。

第i行两个X的位置分别是什么?主对角线上的X在第i列,副对角线上的X在第N-1-i列。如果这两个位置相等(说明两条对角线在这一行相交于同一个格子,只发生在N为奇数且i恰好是正中间那一行的时候),这一行就只输出一个X。

这种写法的价值在于,它逼着你去推公式,而不是无脑遍历。用这种思路写出来的代码,通常是把一行字符串先拆成几段来输出,比如先输出左边那一段点,再输出X,再输出中间那一段点,再输出X,最后输出右边那一段点。逻辑上稍微绕一点,但对理解“下标的对称关系”特别有帮助。

2.3 两种思路的对比与选型建议

从考试得分的角度来说,第一种思路更稳妥。它的代码短,逻辑直接,不容易在构造字符串时把中间段的长度算错。第二种思路代码也不长,但中间涉及几个关于列坐标的计算,稍不留神,中间段的长度就会多一个点或少一个点。

从学习能力的角度来说,我更建议初学者先把第一种思路写熟练,然后逼自己用第二种思路再写一遍。这相当于同一个题目用两种视角各做一遍,第二遍做完之后,你对“副对角线坐标是N-1-i”这个对称关系的理解,会比刷十道简单题都深刻。

选择建议很简单:考场求稳,用思路一;平时训练,两种都要会。我自己批改学生代码时,只要看到有人能用第二种思路写出来,基本可以确定他对下标关系的理解已经过关了。

3. 完整参考代码与逐段讲解

3.1 C++版参考代码(思路一)

GESP考试里使用C++的考生最多,这里给出最实用的版本。

#include <iostream> using namespace std; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j || i + j == n - 1) { cout << 'X'; } else { cout << '.'; } } cout << endl; } return 0; }

这段代码的核心就一个if条件。两个竖线是逻辑或,意思是只要满足两个条件中的任意一个,就输出X。注意,这里用的是英文双引号或单引号,'X'是字符常量,输出单个字符用单引号,千万不要写成"X",字符串和字符在C++里是两种不同的类型,虽然在这个场景下结果可能一样,但养成好习惯总没错。

还有一个细节值得说:内层循环里每输出一个字符,没有输出空格。有些同学会习惯性地在字符后面加一个空格,想着让矩阵看起来更整齐。但如果题目样例里没有空格,改卷时比对的是原始输出,多出来的空格很可能被判错。以题目描述和样例为准,不需要自行美化。

3.2 Python版参考代码

Python写起来更简洁,适合平时练习和快速验证思路。

n = int(input()) for i in range(n): for j in range(n): if i == j or i + j == n - 1: print('X', end='') else: print('.', end='') print()

这里有几个Python特有的关键点。第一,print默认会在末尾换行,用end=''可以取消换行,让同一行的字符连续输出。第二,内层循环结束后,用一个空的print()来实现换行,很多人第一次写会漏掉这一步,结果所有字符都挤在同一行上。第三,Python的range(n)生成的是0到n-1的整数序列,和C++里从0到n-1的循环天然一致,反而不容易出现下标偏移问题。

还有一种更Pythonic的写法是逐行生成字符串再输出:

n = int(input()) for i in range(n): row = '' for j in range(n): row += 'X' if i == j or i + j == n - 1 else '.' print(row)

这种写法把一行内容先拼成字符串,再一次性输出。好处是逻辑清晰,而且更容易在debug时print出row来看每一行生成得对不对。虽然效率上多了一次字符串拼接,但对于这种规模的问题完全无所谓。

3.3 输入输出细节与复杂度分析

输入只有一个整数n,用cin或input()读取都可以。读取时要注意,有些版本题目可能会先读一个字符,再读n,或者读入n后还要再读两个字符作为矩阵的填充字符。如果有两字符,典型的C++读法是:

int n; char ch1, ch2; cin >> n >> ch1 >> ch2;

cin在读取字符时会自动跳过空格和换行,所以不会读进脏数据。Python用split也可以轻松处理:

parts = input().split() n = int(parts[0]) ch1 = parts[1] ch2 = parts[2]

但GESP这道题本身一般不需要读字符,直接用X和点就行。如果你在考场上不确定,就仔细看输入格式描述,比什么都重要。

时间复杂度是O(n²),因为要把整个矩阵每个字符都输出一遍。如果n=100,那就是1万个字符,毫无压力;如果n=1000,那就是100万个字符,C++的cout依然能应付,Python的print在循环里输出100万次会稍慢,但也在可接受范围内。空间上,如果边遍历边输出,额外空间是O(1)级别;如果用二维数组存储再输出,那就是O(n²)。对这种题,边遍历边输出是更优的选择。

4. 实战中的常见错误与排查思路

4.1 行列下标从0还是从1开始引发的偏移

这个问题是我在教学时遇到频率最高的错误。很多同学在草稿纸上画矩阵时,习惯把第一行第一列标为1,于是写出了i + j == n + 1这样的条件,运行结果却怎么都不对。原因很简单:代码里数组下标从0开始,第一行是i=0,第一列是j=0,对角线交点在第(n-1)/2行,而不是第n/2行。

判断自己是不是下标弄错了,有个快速办法:拿n=3代入你写的条件。如果是0基下标,主对角线是(0,0)(1,1)(2,2),副对角线是(0,2)(1,1)(2,0);如果是1基下标,主对角线是(1,1)(2,2)(3,3),副对角线是(1,3)(2,2)(3,1)。你写代码时用哪套规则,就把样例代入哪套规则,手算两遍,错误立刻暴露。

我个人的建议是:写代码一律使用0基下标,因为数组、循环、字符串下标都是0基的,保持一致可以少一层换算。草稿纸上画图时可以随便标,但落到代码里的条件一定是i+j==n-1而不是n+1。

4.2 输出格式问题:换行与多余空格

图形输出题最冤的丢分点,是格式错误。常见情况有三种。

第一种是行末多了空格。有些同学可能觉得X后面加个空格会更整齐,结果和样例完全不一致。大部分在线评测系统会把你的输出和标准输出逐字符比对,多一个空格就是错误答案。

第二种是换行位置不对。内层循环还在运行时就去换行,或者整个矩阵输出完之后才换行,都会让图形完全变形。正确的位置是在一行的所有列都输出完之后再换行,也就是内层循环结束、外层循环还没进入下一次时。

第三种是最后一行之后多了一个空行。多输出一个换行符虽然在某些评测系统里会被容忍,但在严格比对时也会出问题。如果你在行末统一用了endl,最后一行之后多一个空行是很正常的,但如果题目要求严格匹配,可以把换行逻辑改成前面n-1行输出换行,最后一行不输出。不过大多数GESP题目不会卡得这么死,这里只是提示有这种可能。

4.3 中间格子重复输出的问题

前面提到过,当n是奇数时,两条对角线会交叉在正中间那个格子上。一个常见的错误写法是:

if (i == j) cout << 'X'; if (i + j == n - 1) cout << 'X'; else cout << '.';

这段代码在中间格子上会先因为第一个if输出一个X,又因为第二个if的条件成立再输出一个X,导致这一行出现两个连续的X,整个矩阵就错了。

正确的写法是使用“或”条件把这些判断合并成一个,或者用else if把两种情况隔开:

if (i == j || i + j == n - 1) cout << 'X'; else cout << '.';

如果你非要分开写,那也得是:

if (i == j || i + j == n - 1) cout << 'X'; else cout << '.';

本质上还是合并。理解原理很重要:一个格子只能输出一个字符,所以判断条件之间必须互斥,或者通过逻辑或合并后只执行一次输出。

还有一个冷知识:当n是偶数时,两条对角线在格子的交界处相交,不会落在任何格子上,所以每一行都有两个X;只有当n是奇数时,正中间那一行才只有一个X。这个几何直觉理解了,你甚至能提前判断出输出结果长什么样,对debug非常有帮助。

4.4 大N下的效率与缓存策略

这道题本身的n不会太大,但图形输出类题目到了更高等级,可能会出现n比较大、需要输出到文件的情况,所以提前建立性能意识没有坏处。

如果你用C++,cout在默认情况下和C的stdio是同步的,逐字符输出1百万个字符会有一点性能损耗。你可以用ios::sync_with_stdio(false);关掉同步,或者在字符量很大时把整行输出而不是逐字符输出。

如果你用Python,逐字符print确实慢,推荐用字符串拼接后一次性print。这是因为Python的IO操作开销远大于字符串操作。改写成第二种思路(逐行构造)之后,每行只调用一次print,性能会有明显提升。

当然,对GESP二级的题目来说,n一般到不了需要担心性能的程度。但你可以把这道题当作一个起点,养成“循环里少做IO”的习惯,对后续学习会很有帮助。

5. 从一道二级题延伸出去的能力提升

5.1 六个值得动手练的变体题

一道题做会了不算真会,能举一反三才算。我建议你在X字矩阵的基础上,往下练这六个变体,难度由浅入深。

第一,改变字符。比如用“*”画对角线,用空格填充其余位置,或者读入两个字符,一个用于对角线,一个用于其他位置。这个变体练的是“参数化输出”,代码结构不变,但你要学会从题目描述里提取字符变量。

第二,只画主对角线。也就是只有左上到右下这一条斜线,其余位置填充点。这个题练的是把复杂条件简化为单一条件,从i == j || i + j == n - 1 变成只有i == j。

第三,只画副对角线。相当于只画右上到左下这一条斜线,这对理解“行号加列号等于常数”特别有效。

第四,画外框加对角线。矩阵的最外一圈也输出X,中间两条对角线也输出X,其余输出点。这个进阶题同时考察了边界判断和对角线判断,条件会变成四组,是很好的综合训练。

第五,菱形输出。给定n,输出一个由字符构成的菱形,中心行最长,上下逐行对称缩短。这个题开始涉及行与列之间的绝对值关系,对数学思维的考察更强。

第六,蛇形矩阵或螺旋矩阵。这些已经接近二级考试后面等级的难度了,但它们本质上都是“用下标关系控制输出内容”的题目,底层逻辑和X字矩阵是一脉相承的。如果你能把X字矩阵讲给别人听,说明你真的学会了。

5.2 这类题目的通用解题模板

做了足够多的图形输出题之后,你会总结出一套自己的模板。我的模板一般是四步。

第一步,读入参数,确定矩阵规模。第二步,用双重循环框定每个格子的行号i和列号j。第三步,写一个关于(i, j)的判断条件,决定这个格子输出什么字符。第四步,控制好行末换行位置。

这个模板可以套用到百分之八九十的图形输出题上。判断条件是核心,也是拉开差距的地方。判断条件怎么写,取决于你对坐标关系的数学抽象能力。最简单的判断就是直接比较,比如i == j;复杂一点的会用绝对值,比如abs(i - j) == 1;再有更复杂的会用距离公式。这些都可以从X字矩阵这个基础题慢慢延伸出来。

5.3 刷题顺序与训练建议

如果你正在准备GESP二级,我的建议是不要只刷真题,而是把图形输出这一类题集中练一练。具体来说,先练各种基础图形:矩形、空心矩形、直角三角形、等腰三角形、菱形、X字矩阵。这些题难度低、反馈快,每道题都能让你对循环和坐标的关系多一分感觉。

练习时要刻意做一些事:每道题都手动模拟一遍小数据,把输出结果写在纸上,再和程序输出对比。不要一上来就写代码,先想清楚“哪个格子输出什么字符”,这一步想明白了,代码只是把它翻译成if语句而已。

这里也可以提一下“对拍验证”。如果有同学已经学到文件读写和随机数了,可以写一个朴素版本的程序作为标准答案,再写一个优化版本的程序,用随机生成的n跑几百次,比较两个程序的输出是否完全一致。这个方法在更高阶段的竞赛训练里非常常见,早点接触没坏处。

5.4 GESP二级图形题的高频考点清单

根据我对近几次考级题目的观察,二级图形输出题高频出现的考点可以整理成一张表。

考点对应能力常见陷阱
双重循环结构行列逻辑是否正确内外层循环顺序写反
对角线条件坐标抽象能力下标从0还是从1混乱
字符输出与换行输出格式控制行末多余空格、换行位置不对
对称关系数学规律总结副对角线常数为n-1或n+1混淆
边界值特例处理能力n=1、n=2时逻辑走不通

这张表你可以考前过一遍,每一行对应的题找两三道练手。比如“边界值”这一栏,就专门去测n=1和n=2的X字矩阵,确认程序输出符合预期。这种针对性的查漏补缺,比漫无目的地刷题高效得多。

写在最后的一点个人体会

这道题我给学生讲过很多次,每次都会发现新的讲法。最开始我只是讲怎么用if条件判断,后来发现很多孩子真正卡住的地方不是条件,而是脑子里没有那张“坐标图”。所以我后来上课,第一件事永远是让学生自己在方格纸上标出行号和列号,把N=5的情况手工画一遍。一旦那张图画出来,写代码就是水到渠成的事了。

如果你现在正卡在这道题上,不要急着看更多题解,找张纸,画出一个5×5的格子,标上行列号,然后圈出所有应该输出X的格子。做完这一步,再回头看你自己的代码,大概率一眼就能看出问题在哪。

这道题看起来只是考级路上的一小块垫脚石,但它背后承载的“坐标思维”,会一路跟着你走到更复杂的算法问题里。能把一张矩阵画明白的人,后面学动态规划、图论,都会轻松很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询