C++ While及Do-while讲解与一本通平台讲解
今天,我来讲解一下 C++ 中 While 以及 Do-while 语句的作用,因为他俩的作用差不多,所以我就混在一起写了(我绝对不会告诉你我是懒得写两篇)。
拖更还不是因为考试...
While
while 的意思是直到,我们就可以非常轻松的看出它的意思,就是满足某种条件时执行其内部的代码,它的结构如下:
while(条件表达式) 语句;
或者是
while(条件表达式)
{
语句1;
语句2;
...
}
还有就是
while(条件表达式);
当 while 语句中的条件表达式成立时,我们就可以执行其中的语句,而当它不成立了,我们就会从 while 语句中退出来,继续执行后面的语句。while 在不确定循环次数时使用,例如输入一列数据,假设读取到了 E 就退出,那么我们可以使用 while 进行循环,判断读入的是否是 E,如果是就退出,否则继续读入,代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
int **in()
{
char a;
while(cin>>a&&a!='E');//字符 a 满足不为 E 时继续循环,否则退出循环
printf("By - December\n");//退出循环后执行 while 后面的语句
return 0;
}
我们可以看到,while 的作用是很方便的,但是随之而来的肯定是其他问题。
Do - While
当你想让 while 循环至少先判断一次时,如果对 while 加上特判的话会显得有些麻烦,所以,C++ 中有一个看似跟 while 长得十分像的东西 do - while 一看它就不简单,还是分开来的,其实并不难,只不过它把要执行的程序放在了 while 的前面,do 的后面,例如:
#include<iostream>
#include<cstdio>
using namespace std;
int **in()
{
char a;
do
{
printf("By - December\n");
}while(cin>>a&&a!='E');//再 do - while 后面要加上冒号
return 0;
}
这段代码与上面的没有太大的区别,只不过一开始会输出一次,多输入几个字符会多弹出几个罢了......
一般来说,只要你学会了 while 语句,do - while 语句自然就十分容易了。
信息学奥赛一本通的题目
2020 - 2023,1085 - 1090,2024 - 2025
do - while 语句的一部分题与 while 语句重复了,可以使用 while 和 do - while 各写一遍,加强对这两个语句的理解与运用。不要像我一样 Ctrl + C + Ctrl + V 。
2020:【例4.5】第几项
这是一道十分典型的求项数的题目,三种循环都可以用,这里用 while 和 do - while 各写一个,代码如下:
while
#include<iostream>
using namespace std;
int **in()
{
int i=0,m,sum=0;//累加的数一定要初始化为0!!!
cin>>m;
while(sum<=m)//判断什么时候不满足这个条件
{
i++;//累加的数每次增加1
sum+=i;//每次sum累加i的数
}
cout<<i<<endl;//输出这个项
return 0;
}
do - while
#include<iostream>
using namespace std;
int **in()
{
int i=0,m,sum=0;
cin>>m;
do//先会执行一次
{
i++;
sum+=i;
}while(sum<=m);//判断是否满足这个条件
cout<<i<<endl;
return 0;
}
较好都写一遍
2021:【例4.6】较大公约数
这道题虽然使用暴力解决(也就是枚举除数,再用两个数分别除,看看是否余数都为零),但是它还有一个更加高级的方法,那就是辗转相除法,效率要比枚举快,推荐使用。
代码如下:
while
#include<iostream>
#include<cstdio>
using namespace std;
int **in()
{
int x,y,z;
scanf("%d%d",&x,&y);
if(x==y)//特判
{
printf("%d\n",x);
return 0;
}
if(x<y) swap(x,y);//将大数作为被除数
z=x;
while(x%y!=0)
{
x=y;
y=z%y;
z=x;
}//辗转相除法的核心代码
printf("%d\n",y);
return 0;
}
do - while(其实差不多)
#include<iostream>
#include<cstdio>
using namespace std;
int **in()
{
int x,y,z;
scanf("%d%d",&x,&y);
if(x==y)//特判
{
printf("%d\n",x);
return 0;
}
if(x<y) swap(x,y);//将大数作为被除数
z=x;
do
{
x=y;
y=z%y;
z=x;
}while(x%y!=0);//辗转相除法的核心代码
printf("%d\n",y);
return 0;
}
同样较好都写一遍(虽然十分相像...)
2022:【例4.7】**小n值
这一题因为不确定循环次数,所以使用 while 或 do - while 。
#include<iostream>
using namespace std;
int **in()
{
int i=0,m;
double sum=0;//要使用单/双精浮点数
cin>>m;
while(sum<m)//使用题目给出的条件进行判断
{
i++;
sum+=1.0/i;//求和
}
cout<<i<<endl;
return 0;
}
do - while 就不贴出来了,都是差不多的。
2023:【例4.8】数据统计
分别使用求出**小,较大值,再计算出平均值即可。
代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
int **in()
{
int x,minn=1100,**xn=-1100,sum=0,tot=0;//初始化一定不能忘
while(scanf("%d",&x)!=EOF)//"!=EOF"是指判断输入是否成功
{
if(x<minn) minn=x;
if(x>**xn) **xn=x;
sum+=x;tot++;
}
printf("%d %d %.3f\n",minn,**xn,double(sum)/double(tot));
return 0;
}
1085:球弹跳高度的计算
当时是用 do - while 写的,所以(代码如下):
#include<iostream>
#include<cstdio>
using namespace std;
int **in()
{
double a,b,h;
int i=2;
scanf("%lf",&h);
a=h;
b=h/2.0;
do
{
a=a+2*b;
b=(1.0/2)*b;
i++;
}
while(i<=10);//按照步骤依次计算即可
printf("%g\n%g",a,b);
return 0;
}
这题本身不难,不会做的人多了,它也就变难了。只要你清楚了步骤就可以写出来。
1086:角谷猜想
此题难点:无,跟上一题是一样的,按照题目一步步做就绝对不会错。
代码如下:
#include<iostream>
using namespace std;
int **in()
{
int x,y,z;
cin>>x;
while(x!=1)//特判输入为1的情况
{
if(x%2==0)//如果是2的倍数
{
cout<<x<<"/2="<<x/2<<endl;
x=x/2;
}
else//如果不是2的倍数
{
cout<<x<<"*3+1="<<x*3+1<<endl;
x=x*3+1;
}
}
cout<<"End"<<endl;
return 0;
}
这题本身不难...
1087:级数求和
这就像是 2022 题的升级版,但实话是并没有太大的区别,仔细思考就可以想的到。
代码如下:
#include<iostream>
using namespace std;
int **in()
{
int k,n=1;
double sum=1;
cin>>k;
while(sum<=k)
{
n++;
sum+=1.0/n;
}
cout<<n<<endl;
return 0;
}
是不是很像 2022 的代码 ?
1088:分离整数的各个数
这里就需要仔细的思考才可以推导出这段代码。
这段代码的主要意义是截取出末尾的位数,并进行下一次的计算,整个设计都十分的巧妙。
代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
int **in()
{
int a,n,b=10,c=0,s=0;
cin>>n;
do
{
a=(n%b-c)/(b/10);//截取
c=a;
s=a*(b/10)+s;//s用于判断这段数字是否截取完了
b=b*10;//扩大截取位
cout<<a<<" ";//输出
}
while(n>s);
return 0;
}
但是,如果你学习了字符串后,你一定会抛弃这种复杂,难以理解的算法的。因为字符串好理解还简单,代码如下:
#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
int **in()
{
string x;
getline(cin,x);
int i,l=x.size();
for(i=l-1;i>=0;i--) cout<<x<<' ';
return 0;
}
又简洁,又易懂,是做题的不二选择。
1089:数字反转
这道题如果纯用数学方法的话,估计要想较久,这题使用字符串仍然要好用许多。
代码如下(数学方法):
#include<iostream>
using namespace std;
int **in()
{
int n,sum=0;
cin>>n;
if(n<0)
{
cout<<"-";
n=-n;
}
while(n)
{
sum=sum*10+n%10;//对正数进行反转
n/=10;
}
cout<<sum<<endl;
return 0;
}
但是这篇文章不是学字符串...
1090:含k个3的数
按照题目意义写,分离各个数位进行判断即可
代码如下:
#include<iostream>
using namespace std;
int **in()
{
int m,k,g,s,b,q,w,num=0;//累加的 sum 一定要清零!!!
cin>>m>>k;
w=m/10000;//分离万位
q=m%10000/1000;//分离千位
b=m%1000/100;//分离百位
s=m%100/10;//分离十位
g=m%10;//分离个位
if(g==3) num++;//判断个位是否为3
if(s==3) num++;//判断十位是否为3
if(b==3) num++;//判断百位是否为3
if(q==3) num++;//判断千位是否为3
if(w==3) num++;//判断万位是否为3
if(num==k&&m%19==0) cout<<"YES"<<endl;//如果有 k 个 3 且可以被 19 整除
else cout<<"NO"<<endl;//不满足时
return 0;
}
不难...
2024:【例4.10】末两位数
这道题乍一看,诶!还挺简单的啊?只要把这个计算出来然后取后两位不就成了吗?
但是,事实却并非如此,你要是这样做,肯定会超出空间限制(简称MLE),因为一个程序要在系统规定的空间大小内完成程序的执行。要知道空间复杂度的概念,它表示一个程序运行所需占用的空间大小,表示为 O(Memory) 的形式,其中 Memory 为占用空间,通常空间复杂度用于表示输入数据大小,如输入 2^31 ( 2,147,483,648 ) 这么大的数,int 类型就存不下了,因为 int 的存储范围为 ± 2 ^ 31 - 1 ( ± 2,147,483,647 ),要用 long long 类型存储,long long 的存储范围要比 int 大许多,为 ± 2 ^ 63 -1 ( ± 9,223,372,036,854,775,807 ) ,一旦存入的数据超过了这个此数据类型的范围,就会出现 溢出 现象,即值从极限大变为极限小,从极限小变为极限大,这样的反转,对程序危害极大,在计算空间复杂度时通常取计算过程中的较大值。
这题如果计算出结果的空间复杂度为 : O (),超级恐怖,而说明 n 最坏情况下为 1999,这样算出来的数据,怎么可能存的下?
其结果为19027373411336818260390395849490...(此处省略6562个0)...00
那我们应该怎么解呢?想一下,我们在计算次方时真的需要保留所有位数吗?其实不用,百位以上对后两位根本没有影响,且它只要较后的两位数。所以,我们可以每次保留两位进行计算,这样就不会超出限制了。
代码也是十分简短 ( 但是为啥要放在 do - while 呢??? ) :
#include<iostream>
using namespace std;
int **in()
{
int i,n,sum=1;//初始化为1,否则无法乘
cin>>n;
for(i=1;i<=n;i++) sum=sum*1992%100;//每次取后两位并乘起来
cout<<sum<<endl;//直接输出
return 0;
}
只要思考好了就不是问题
2025:【例4.11】体操队
这题就一个答案。这不是明摆着直接算吗?根据题意可以知道结果为 301 个人,当然也可以用 while 求出来,枚举人数即可,代码如下:
#include<iostream>
using namespace std;
int **in()
{
int n=7;//人数不可能少于7人(这个优化没啥效果...)
while(true)//不停枚举
{
n+=2;//因为排成两行多一人说明人数为奇数,直接跳过偶数,增加速度(当然也没啥效果)
if(n%3==1&&n%4==1&&n%5==1&&n%6==1&&n%7==0)//是否满足给出条件
{
cout<<n<<endl;//如果满足就输出
return 0;//直接结束,不用继续干了
}
}
}
这样的题目也可以直接算...
并且有着更加简单的代码:
#include<iostream>
using namespace std;
int **in()
{
cout<<301<<endl;
return 0;
}
所以,301 就是答案了
题目都讲完了,你是否都会了呢?
转载:感谢您阅览,转载请注明文章出处“来源从小爱孤峰知识网:一个分享知识和生活随笔记录的知识小站”。
链接:C++ While及Do-while讲解与一本通平台讲解http://www.gufeng7.com/niaolang/1847.html
联系:如果侵犯了你的权益请来信告知我们删除。邮箱:119882116@qq.com
上一篇: C++ 入门讲解
下一篇: C++ 循环嵌套讲解