文章目录
- 前言
- 一、for循环
- 1.导入
- 2.语法
- 3.使用场景
- 4.条件控制
- 5.小结
- 二、例题讲解
- 问题:1264 - 4位反序数
- 问题:1085 - 寻找雷劈数
- 问题:1057 - 能被5整除且至少有一位数字是5的所有整数的个数
- 问题:1392 - 回文偶数?
- 问题:1090 - 同因查找
- 问题:1446. 人口增长问题
- 三、总结
- 四、感谢
前言
在先前的学习旅程中,我们探索了程序设计的基础砖石——顺序结构与分支结构。现在,我们踏上了新征途,深入循环结构的奥秘境地。循环,那是一种魔法,让指令序列在满足条件时重复施展,直至咒语终止。就像《西游记》里的奔波儿灞与灞波儿奔,两者相辅相成对,相似又各异,循环结构中的for与while亦是如此,既有共通点,又各自独异处。
循环结构,特别是for循环,如同编程中的时间轮回,让代码在特定条件下周而复现,赋予程序无限可能。我们从语法差异、应用场景、控制机制到选择考量,全方位剖析for与while的同与别,助你在编程征途中,握选得宜剑。
学习路线:C++从入门到NOI学习路线
学习大纲:C++全国青少年信息学奥林匹克竞赛(NOI)入门级-大纲
一、for循环
1.导入
在上一节中,我们讲解了循环结构和while循环。相信大家通过一系列的题目练习对while循环已经掌握的炉火纯青
那今天我们就要学习一种新的循环结构———for循环。
for循环和while循环有什么区别吗?
它俩的区别就像是奔波儿灞,灞波儿奔。
既有相同之处又有不同之处。
我们将从以下几点来对比两个循环结构。
2.语法
首先从语法上比较,相同之处。
while循环和for循环都有初始化、条件表达式、迭代表达式。
- 初始化:在循环开始之前执行一次,通常用于设置循环控制变量。
- 条件表达式:在每次循环迭代前检查,如果结果为真(非零),则执行循环体;如果为假(零),则循环结束。
- 迭代表达式:在每次循环体执行完毕后执行,通常用于更新循环控制变量。
不同的地方在哪里呢?
它们摆放的位置不一样!!!
while循环的括号里只有条件判断部分,初始化和迭代更新的操作需编写在循环括号外。
初始化;
while (条件表达式) {
// 循环体
迭代表达式;
}
而for循环语法结构更加紧凑,集成了初始化、条件判断和迭代更新三个环节于一体。其一般形式如下:
for (初始化; 条件表达式; 迭代表达式) {
// 循环体(要重复执行的代码)
}
3.使用场景
- for循环:
- 当循环次数固定或可预知时,如遍历数组或容器的所有元素。
- 需要同时初始化、检查条件和更新循环变量时,代码更加整洁。
- while循环:
- 当循环的持续依赖于一个可能在循环过程中变化的条件时。
- 对于循环次数不确定,或需要在满足特定条件时开始循环的情况更为合适。
- 当初始化或迭代更新操作较为复杂,不适合放在简短的循环头部时。
4.条件控制
- for循环:
由于其结构特点,循环控制(包括初始化、条件检查和迭代更新)更规范,易于理解和维护,但灵活性相对较低。
- while循环:
提供了更高的灵活性,因为条件判断之外的其他操作都可以自由安排,适合复杂的循环控制逻辑,但可能因为控制流程分散而不易阅读和调试。
5.小结
选择for循环还是while循环,应基于具体问题的性质和编程习惯。for循环在处理已知迭代次数或有明确迭代模式的情况时更佳,而while循环则在循环条件更灵活、复杂时展现其优势。理解两者的异同,能帮助你更有效地选择合适的循环结构来解决问题。
二、例题讲解
问题:1264 - 4位反序数
类型:for循环
题目描述:
设 N 是一个四位数,它的 9 倍恰好是其反序数,求 N 。
反序数就是将整数的数字倒过来形成的整数。例如: 1234 的反序数是4321 。
输入:
无。
输出:
输出 N 这个四位数。
1.分析问题
- 已知:所有的四位数N;
- 未知:找出符合条件的数;
- 关系:满足N * 9 = temp,其中temp是N的反序数。
2.定义变量
- 初始化变量i为1000,这是因为N是一个四位数,所以搜索范围从1000开始。
- 声明变量temp用于存储N的反序数。
//二、数据定义
int i=1000,temp;
3.输入数据
无。
4.数据计算
使用一个for循环遍历1000到9999之间的所有整数(包括两端)。
- 在循环内部,首先通过一系列的除法和取余运算计算出i的反序数并存入temp。具体操作为:
- i%10得到个位数,
- i/10%10得到十位数,
- i/100%10得到百位数,
- i/1000得到千位数,注意这里没有取余是因为前面的乘法操作已经确保了结果在正确的位置上。
- 然后按照反序重新组合这些数字形成temp。
- 接着检查i*9是否等于temp。如果相等,说明找到了符合条件的N。
//四、数据计算
for(;i<10000;i++){
temp=i%10*1000+i/10%10*100+i/100%10*10+i/1000;
if(i*9==temp){
//五、输出结果
cout<<i<<endl;
}
}
完整代码如下:
#include <iostream>
using namespace std;
int main() {
// 一、分析问题
// 目标:寻找一个四位数N,使得N乘以9等于其反序数(即N的数字逆序排列形成的数)。
// 二、数据定义
int i = 1000, temp; // 初始化计数器i为1000(四位数起始),temp用于存储当前i的反序数
// 三、遍历并计算
// 从1000到9999遍历所有四位数
for (; i < 10000; i++) {
// 计算当前数i的反序数temp
// 方法是将i的各位数字分离并以相反顺序重新组合
temp = (i % 10) * 1000 + (i / 10 % 10) * 100 + (i / 100 % 10) * 10 + (i / 1000);
// 四、条件判断
// 检查当前数i乘以9是否等于其反序数temp
if (i * 9 == temp) {
// 五、输出结果
// 打印满足条件的数i
cout << i << endl;
}
}
// 六、程序结束
return 0; // 程序执行完毕,返回0表示成功结束
}
问题:1085 - 寻找雷劈数
类型:for循环
题目描述:
把整数 3025 从中剪开分为 30 和 25 两个数,此时再将这两数之和平方,计算结果又等于原数。
(30+25)×(30+25)=55×55=3025 ,这样的数叫“雷劈数”。
求所有符合这样条件的四位数。(ab+cd)×(ab+cd)=abcd
输入:
无
输出:
若干行,每行一个雷劈数,从小到大输出。
1.分析问题
- 已知:所有的四位数N;
- 未知:找出符合条件的数;
- 关系:满足条件(AB + CD) * (AB + CD) = ABCD。
2.定义变量
- 定义两个整型变量ab和cd,分别用来存储四位数分解后的前两位和后两位。
//二、数据定义
int ab,cd;
3.输入数据
无。
4.数据计算
使用for循环遍历所有四位数(1000到9999)。
- 对于每一个遍历到的数i,通过整除和取余操作将其分为两部分:ab = i / 100(前两位),cd = i % 100(后两位,注意这里得到的是一个0-99的数,但作为计算目的,这不影响结果)。
- 判断条件(ab + cd) * (ab + cd) == i是否成立,即当前数i是否等于其前两位与后两位数字之和的平方。
- 如果条件满足,说明找到了一个雷劈数。
//四、数据计算
for(int i=1000;i<10000;i++){
ab=i/100;
cd=i%100;
if(i==(ab+cd)*(ab+cd)){
//五、输出结果
cout<<i<<endl;
}
}
完整代码如下:
#include <iostream>
using namespace std;
int main() {
// 一、分析问题
// 目标:寻找所有的“雷劈数”,即满足条件的四位数ABCD,其中AB和CD均为两位数,
// 且该四位数等于(AB + CD)乘以(AB + CD)的结果。
// 二、数据定义
int ab, cd; // 分别用于存储四位数的前两位和后两位组成的两位数
// 三、遍历四位数范围进行计算
for (int i = 1000; i < 10000; i++) { // 从最小的四位数1000开始,到最大的四位数9999
// 提取当前四位数的前两位(ab)和后两位(cd)
ab = i / 100; // 整除100得到前两位组成的数字
cd = i % 100; // 取模100得到后两位组成的数字,注意结果包含后两位,即使第一位为0
// 四、条件判断
// 检查当前数i是否等于其前两位与后两位数字之和的平方
if (i == (ab + cd) * (ab + cd)) {
// 五、输出结果
// 当找到满足条件的雷劈数时,输出该数
cout << i << endl;
}
}
// 六、程序结束
return 0; // 程序执行完毕,返回0表示成功
}
问题:1057 - 能被5整除且至少有一位数字是5的所有整数的个数
类型:for循环
题目描述:
找出1∼N 中能被 5 整除且至少有一位数字是 5 的所有整数的个数。(N<32767)。
输入:
输入只有一行,只有 1 个整数 N 。
输出:
输出只有一行(这意味着末尾有一个回车符号),包括 1 个整数。
样例:
输入:
9999
输出:
1271
1.分析问题
- 已知:1-N的整数 ;
- 未知:能被5整除且至少有一位数字是5的所有整数的个数sum ;
- 关系:%5==0 个位=5,十位=5,百位=5,千位=5 。
2.定义变量
- 定义整型变量n用于存储用户输入的上限值。
- 定义整型变量sum初始化为0,用于累计满足条件的整数个数。
//二、数据定义
int n,sum=0;
3.输入数据
- 使用cin >> n;从标准输入读取一个整数N,作为搜索范围的上限。
//三、数据输入
cin>>n;
4.数据计算
- 使用for循环,初始值设为5(第一个同时满足能被5整除和包含数字5的整数),每次循环增加5(保证整除5的特性),直到达到或超过N。
- 在循环体内,使用一系列条件语句检查当前数i的每一位(个位、十位、百位、千位)是否含有数字5。如果任何一个位上的数字为5,则累加器sum加1。
- 注意:这里通过i%10、i/10%10、i/100%10、i/1000%10分别获取个位、十位、百位、千位上的数字。
//四、数据计算
for(int i=5;i<=n;i+=5){
if(i%10==5||i/10%10==5||i/100%10==5||i/1000%10==5){
sum++;
}
}
5.输出结果
- 输出满足条件的整数总数。
//五、输出结果
cout<<sum;
完整代码如下:
#include <iostream>
using namespace std;
int main() {
// 一、分析问题
// 目标:计算1到N之间(包括N),既能被5整除又至少包含一个数字5的所有整数的个数。
// 二、数据定义
int n, sum = 0; // n为用户输入的上限值,sum用于记录满足条件的数的个数,初始化为0
// 三、数据输入
cin >> n; // 从用户那里接收一个整数N,作为搜索的上限
// 四、数据计算
for (int i = 5; i <= n; i += 5) { // 从5开始遍历,每次增加5,确保数能被5整除
// 检查当前数i的各位(个位、十位、百位、千位)是否有5
if ( i % 10 == 5 // 检查个位是否为5
|| (i / 10) % 10 == 5 // 检查十位是否为5,先除以10再取余
|| (i / 100) % 10 == 5 // 检查百位是否为5
|| (i / 1000) % 10 == 5) { // 检查千位是否为5
sum++; // 如果当前数的任何一位是5,sum加1
}
}
// 五、输出结果
cout << sum; // 输出满足条件的整数个数
return 0; // 程序执行完毕,返回0表示成功
}
问题:1392 - 回文偶数?
类型:for循环
题目描述:
小明发现有一类数非常有趣,他们正过来读和反过来读是一样的,比如:121、202、383 等,小明给这类数起了一个名字,叫做回文数。
请你写程序帮助小明找出所有 3 位的既是回文数,又是偶数的数,比如: 202 就是满足条件的数,而 121 虽然是回文数但不是偶数。
输入:
无。
输出:
所有满足条件的 3 位的回文偶数,每行 1 个。
1.分析问题
- 已知:所有的3位数;
- 未知:所有3 位的既是回文数,又是偶数的数;
- 关系:%2==0是偶数 、i % 10 == i / 100是回文数。
2.定义变量
无。
3.输入数据
无。
4.数据计算
- 使用for循环,初始值设为100(第一个三位偶数),每次循环递增2,直接跳过奇数,提高效率。
- 在循环内部,使用条件if(i%10==i/100)来判断当前数i是否为回文数。这里检查了百位和个位是否相等,适用于三位数的回文判断。
- 当i满足既是偶数(由于循环增量为2,保证了这一点)又是回文数的条件时,执行输出操作。
//四、数据计算
for(int i=100;i<=998;i+=2){
if(i%10==i/100){
//五、输出结果
cout<<i<<endl;
}
}
5.输出结果
- 使用cout<<i<<endl;输出满足条件的数,即既是回文数又是偶数的三位数。
完整代码如下:
#include <iostream> // 包含标准输入输出流库
using namespace std; // 使用std命名空间,简化cout和endl的使用
int main() { // 程序入口点
// 一、分析问题
// 目标:找出所有的三位数中,既是回文数也是偶数的数。
// 回文数特点:正着读和倒着读都一样的数,对于三位数而言,意味着百位和个位数字相同。
// 偶数特点:能被2整除,即数字末尾是0、2、4、6、8。
// 二、数据定义与初始化
// 通过for循环变量i来遍历所有可能的三位数,起始值100(第一个三位数),终止值998(最后一个符合条件的偶数三位数)
// 三、数据处理(遍历与判断)
for (int i = 100; i <= 998; i += 2) { // 遍历所有三位偶数
// 判断条件:i的个位数(i%10)等于百位数(i/100,注意这里进行了整除,得到的是去掉个位和十位后的数)
if (i % 10 == i / 100) {
// 四、结果输出
// 当找到一个满足条件的数时,将其输出
cout << i << endl; // 输出该数并换行
}
}
return 0; // 五、程序结束
// 表示程序成功执行完毕,返回操作系统一个状态码0,通常代表没有错误。
}
问题:1090 - 同因查找
类型:for循环、简单循环
题目描述:
求出 10 至 1000 之内能同时被2、3、7 整除的数,并输出。
每行一个。
输入:
无。
输出:
按要求输出满足条件的数,每行 1 个。
1.分析问题
- 已知:10至1000的数 ;
- 未知:同时被2、3、7整除的数;
- 关系:2、3、7都是素数,即除了1和本身不能被其他数整除 。所以想同时被2、3、7整除,那么必然能整除2 * 3 * 7 。
2.定义变量
无。
3.输入数据
无。
4.数据计算
- 通过for循环,变量i从10开始递增到999(不包含1000),遍历这个区间内的所有整数。
- if条件语句检查当前数i是否能被237(即42,2、3、7的最小公倍数)整除。能被42整除意味着该数可以同时被2、3、7整除。
- 当i满足条件时,使用cout << i << endl;输出这个数并换行,以列表形式展示所有满足条件的整数。
//四、数据计算
for(int i=10;i<1000;i++){
if(i%(2*3*7)==0){//最小公倍数
//五、输出结果
cout<<i<<endl;
}
}
完整代码如下:
#include <iostream> // 引入标准输入输出流库,使得我们可以使用cout进行输出等操作。
using namespace std; // 使用std命名空间,这样可以直接调用cout、cin等而无需前缀std::。
int main() { // 定义主函数,程序的执行从这里开始。
// 一、问题分析说明
// 目标:找出10至1000间能同时被2、3、7整除的数。
// 逻辑:由于2、3、7均为素数,它们的最小公倍数即它们的乘积(2*3*7=42),任何能被这三数整除的数也能被42整除。
// 三、数据处理部分 - 开始循环遍历指定范围内的数
for(int i = 10; i < 1000; i++) { // 初始化i为10,当i小于1000时循环继续,每次循环i增加1。
// 判断当前数i是否能被2、3、7的最小公倍数42整除
if(i % (2*3*7) == 0) { // 使用取模运算符(%)检查i除以42的余数是否为0,如果是,则i能被42整除,也就是能同时被2、3、7整除。
// 五、结果输出 - 打印满足条件的数
cout << i << endl; // 输出满足条件的数i,并在每个数后换行以便于查看。
}
}
return 0; // 主函数执行完毕,返回0表示程序正常结束。
} // 主函数结束
问题:1446. 人口增长问题
类型:循环应用
题目描述:
我国现有 x 亿人口,按照每年 0.1% 的增长速度,n 年后将有多少人?
输入:
一行,包含两个整数 x 和 n ,分别是人口基数和年数,以单个空格分隔。
输出:
输出最后的人口数,以亿为单位,保留到小数点后四位。(1≤x≤100,1≤n≤100) 。
样例:
输入:
13 10
输出:
13.1306
1.分析问题
- 已知:初始人口为 x 亿人,年增长率为0.1%。
- 未知:n 年后的人口总数。
- 关系:每年的人口增长量为当前人口的0.1%,因此,n 年后的总人口可以通过逐年累加当前年人口的0.1%来计算。
2.定义变量
- 定义整型变量 n 存储年数。
- 定义双精度浮点型变量 x 存储以亿为单位的初始人口数。
//二、数据定义
int n;
double x;
3.输入数据
- 使用 cin 从标准输入读取 x(初始人口)和 n(年数)的值。
//三、数据输入
cin>>x>>n;
4.数据计算
使用 for 循环模拟 n 年的增长过程。每年:
- 当前人口数 x 增加其0.1%(即 x * 0.001)。
//四、数据计算
for(int i=1;i<=n;i++){
x+=x*0.001;
}
5.输出结果
- 使用 cout 输出最终人口数,fixed 和 setprecision(4) 用于设定输出格式,确保人口数保留四位小数。
//五、输出结果
cout<<fixed<<setprecision(4)<<x;
完整代码如下:
#include<bits/stdc++.h> // 包含标准库中的所有常用头文件,方便编程但可能增加编译时间
using namespace std; // 使用std命名空间,省略std::前缀
int main(){ // 程序的主入口函数
// 一、分析问题
// 给定初始人口(x 亿),年增长率(0.1%),求n年后的总人口
// 二、数据定义
int n; // 定义一个整数n,存储年数
double x; // 定义一个双精度浮点数x,存储初始人口数(单位:亿)
// 三、数据输入
cin >> x >> n; // 从用户输入中读取初始人口x(亿)和年数n
// 四、数据计算
for(int i = 1; i <= n; i++){ // 循环n次,模拟每一年的增长
x += x * 0.001; // 每年的人口增长为原有人口的0.1%,累加到x上
}
// 五、输出结果
cout << fixed << setprecision(4) << x; // 设置输出格式为固定小数点,保留四位小数,然后输出最终人口数x
return 0; // 主函数正常结束,返回0表示成功执行
}
三、总结
循环,编程艺术之轮转,for与while,循环结构是编程中的两大神器。理解它们的语法构造与适用场景,是在解决编程挑战中的关键。通过实例剖析,我们见证了for循环在具体问题解决中的运用,如求解“4位反序数”、“雷劈数”、“回文偶数”等,以及寻找特定条件数列数的个数。这些实例不仅巩固了for循环的掌握,也展现了循环结构的灵活性与威力,让问题解决变得直观且高效。在NOI的道路上,掌握循环,犹如掌握了通往解谜题的钥匙,开启编程世界的大门扉。
四、感谢
如若本文对您的学习或工作有所启发和帮助,恳请您给予宝贵的支持——轻轻一点,为文章点赞;若觉得内容值得分享给更多朋友,欢迎转发扩散;若认为此篇内容具有长期参考价值,敬请收藏以便随时查阅。
每一次您的点赞、分享与收藏,都是对我持续创作和分享的热情鼓励,也是推动我不断提供更多高质量内容的动力源泉。期待我们在下一篇文章中再次相遇,共同攀登知识的高峰!