乙级的题目训练主要用来熟悉编程语言的语法和形成良好的编码习惯和编码规范。从小白开始逐步掌握用编程解决问题。
思路一: 以终为始分解需求
题设给定了一组学生的姓名、学号、成绩;要求输出成绩最高和成绩最低的学生的姓名和学号;
如果要输出成绩最高和最低学生的信息, 则要知道成绩最高最低的学生是哪个
(更具体地说, 成绩最高最低, 即存在一个学生的成绩比其他同学的成绩都高/都低.)
原问题将转化为: 求给定的学生中, 成绩最高/最低的学生.
这直接引导我们将学生们的成绩进行"大小比较".
由于要对比所有学生, 所以我们想到需要遍历每个学生, 即使用循环语句.
将思路完整表述清楚, 则有如下版本的步骤描述(版本一):
对每个学生进行如下操作:
1. 获取该学生的成绩
2. 使用该学生的成绩与其余学生进行比较.
- 如果他比其余所有学生的成绩都高, 则他就是成绩最高的学生
- 如果他比其余所有学生的成绩都低, 则他就是成绩最低的学生
而如果我们进一步拆解问题为: 求给定学生中, 成绩等于最高成绩的学生 -> 求给定学生成绩中最高的成绩
则将写为如下版本的步骤描述(版本二):
对每个学生进行如下操作:
接下来,我们要将方案翻译成代码, 并且补充一些方案考虑和编码上的细节。
其他数据的存储: 我们考虑【数据存储】是为了【数据使用】, 那么除了数据非存不可的情况(数据不存步骤就无法进行), 存储其他(不存步骤也可以进行)的数据则是为了方便【数据使用】。
比如: 我们存储了最高的成绩, 那么输出最高成绩学生的姓名和学号时, 我们可以用最高成绩去核对哪个学生成绩等于最高成绩, 然后输出他的姓名和学号。
到这里, “存储额外数据是为了方便"就有很好的体现了。我多存了几个数据, 省去了我不存数据还要再次挨个去比较的麻烦(这种多记数据避免多做更多事情的做法, 有个专门的说法"空间换时间”, 起步阶段我们不必细究专有词汇, 之后再展开)
for(每个学生), 操作如下:
循环结束后
已经找到题设要求的答案了, 输出答案吧.
【实际编码会遇到的更细节的问题】
/*
思路一: 以终为始分解需求
题设给定了一组学生的姓名、学号、成绩;要求输出成绩最高和成绩最低的学生的姓名和学号;
如果要输出成绩最高和最低学生的信息, 则要知道成绩最高最低的学生是哪个
(更具体地说, 成绩最高最低, 即存在一个学生的成绩比其他同学的成绩都高/都低.)
原问题将转化为: 求给定的学生中, 成绩最高/最低的学生.
这直接引导我们将学生们的成绩进行"大小比较".
由于要对比所有学生, 所以我们想到需要遍历每个学生, 即使用循环语句.
将思路完整表述清楚, 则有如下版本的步骤描述(版本一):
对每个学生进行如下操作:
1. 获取该学生的成绩
2. 使用该学生的成绩与其余学生进行比较.
- 如果他比其余所有学生的成绩都高, 则他就是成绩最高的学生
- 如果他比其余所有学生的成绩都低, 则他就是成绩最低的学生
而如果我们进一步拆解问题为: 求给定学生中, 成绩等于最高成绩的学生 -> 求给定学生成绩中最高的成绩
则将写为如下版本的步骤描述(版本二):
对每个学生进行如下操作:
1. 获取该学生的成绩
2. 检查该学生是否比之前出现过的最高成绩高.
- 如果成绩比之前出现过的最高成绩高, 则更新目前最高成绩.
3. 检查该学生是否比之前出现过的最低成绩低.
- 如果成绩比之前出现过的最低成绩低, 则更新目前最低成绩.
看完每个学生的成绩后, 我们得到了最高成绩和最低成绩.
- 输出最高成绩学生的姓名即输出成绩等于最高成绩的学生的姓名.
- 输出最低成绩学生的姓名即输出成绩等于最低成绩的学生的姓名.
接下来,我们要将方案翻译成代码, 并且补充一些方案考虑和编码上的细节。
【考虑输入数据和计算过程中数据的存储】
输入数据是学生的姓名、学号和成绩.
过程中会进行比较, 比较会得出结果。
- 如果是使用版本一的步骤, 我们比较的是某个学生(或者叫当前选取的学生)的成绩是否比其他学生都高,
而其他学生是指多个学生, 也是需要挨个比较, 比较的结果是"当前选取的学生比他之外的某个学生高", 如果"是", 继续比较, 如果不是, 更换"当前选取的学生".
对于这种情况, 会发现比较的结果是马上会使用, 而且之后不会再使用的。而【存储数据】是为了【使用数据】, 如果之后不用, 可以不存储数据。
- 如果是使用版本二的步骤, 我们比较的是当前成绩是否比之前看到的最高成绩高, 如果更高, 这个成绩就是之后比较的对象。既然之后需要用来比较, 则需要存储。
其他数据的存储: 我们考虑【数据存储】是为了【数据使用】, 那么除了数据非存不可的情况(数据不存步骤就无法进行), 存储其他(不存步骤也可以进行)的数据则是为了方便【数据使用】。
比如: 我们存储了最高的成绩, 那么输出最高成绩学生的姓名和学号时, 我们可以用最高成绩去核对哪个学生成绩等于最高成绩, 然后输出他的姓名和学号。
而"用最高成绩去核对哪个学生成绩等于最高成绩"是要找到一群学生中, 分最高的学生在哪, 找他的位置。而既然我们在比较的时候记录当前最高成绩. 我们也可以记录最高成绩是在哪个位置出现的。
当然,你可能也想到了, 记录什么是我们可以决定的, 那我直接记录最高成绩出现的时候, 选取的学生的姓名和学号(并且在后面比较中跟着最高成绩一起更新), 然后在比较完之后直接就存储了最高成绩的学生姓名和学号。
到这里, "存储额外数据是为了方便"就有很好的体现了。我多存了几个数据, 省去了我不存数据还要再次挨个去比较的麻烦(这种多记数据避免多做更多事情的做法, 有个专门的说法"空间换时间", 起步阶段我们不必细究专有词汇, 之后再展开)
【考虑如何组织代码逻辑】
1. 数据存储 -> 变量的定义、变量的赋值
2. 比较 -> > = <
3. 挨个比较 -> 循环
- 学生个数是确定的, 对应了 for循环的特点, 所以优先选用for循环而不是while循环
for(每个学生), 操作如下:
如果学生x的成绩比当前最高成绩高, 记录学生x的成绩为当前最高成绩, 记录学生姓名和学号为当前最高成绩的学生姓名和学号;
如果学生x的成绩比当前最低成绩高, 记录学生x的成绩为当前最低成绩, 记录学生姓名和学号为当前最低成绩的学生姓名和学号;
循环结束后, 循环过程中的"当前最高成绩"就变成所有学生中的最高成绩, 记录的姓名和学号就是所有学生中成绩最高的学生姓名和学号。
已经找到题设要求的答案了, 输出答案吧.
【实际编码会遇到的更细节的问题】
1. C语言如何定义字符串, C语言如何定义一组字符串。
2. C语言如何存储字符串,如何存储一组字符串(包括读入数据到变量和赋值数据给变量)
3. C语言中如何对一组字符串进行循环.
以上问题都可以通过搜索引擎找到, "如何想到思路以及如何组织和描述思路"才是核心, 而具体编码上的写法是细枝末节, 起步阶段不抗拒搜索引擎寻找答案, 随着练习的增多和对写法的熟悉, 从记忆中找答案将会取代从搜索引擎找答案
*/
# include
int main(){
int student_amount;
scanf("%d", &student_amount);
char names[student_amount][11];
char student_numbers[student_amount][11];
int scores[student_amount];
for(int i = 0; i < student_amount; i++){
scanf("%s %s %d", names[i], student_numbers[i], &scores[i]);
}
int max_score_index = -1;
int max_score = -1;
int min_score_index = -1;
int min_score = 101;
for (int i = 0; i < student_amount; i++){
if (scores[i] > max_score){
max_score = scores[i];
max_score_index = i;
}
if (scores[i] < min_score){
min_score = scores[i];
min_score_index = i;
}
}
printf("%s %s\n", names[max_score_index], student_numbers[max_score_index]);
printf("%s %s\n", names[min_score_index], student_numbers[min_score_index]);
return 0;
}