一个完成某种特定任务的过程,可分解成一组操作步骤,这组操作步骤即构成一个算法。
一、算法 1.1 算法设计的方法 1.2 算法结构 1.3 条件 二、布尔类型 2.1 布尔类型数据的基本概念 2.2 关系运算符 2.3 逻辑运算符 三、选择语句 3.1 if—else语句的语法 3.2 C++语句条件运算符 3.3 switch-case语句 四、循环语句 4.1 while语句 4.2 do—while语句 4.3 for语句 4.4 逗号“,”运算符 4.5 控制语句 五、算法设计与评价
程序设计过程中,程序员将完成某种程序功能的过程,分解成一组可被计算机执行的操作步骤,这组操作步骤就叫算法。
选择结构和循环结构都需要用到条件,条件成立,我们称这个条件为真,否则称之为假,C++语言使用布尔类型来表达条件的真假,通过关系运算符构成的关系表达式来描述条件。还可以根据逻辑运算符构成的逻辑表达式来符合条件。
使用C++语言,将设计好的算法,编写成一组语句序列,这就是C++源程序,为了描述选择结构和循环结构的算法,C++分别提供了选择语句和循环语句。
布尔(bool)类型:true、false,true和false都是关键字,可以定义布尔类型变量保存布尔型数据,一个布尔型变量占用1个字节,计算机只能存储数值数据,因此计算机内部以1表示true,0表示false。
#include <iostream>
using namespace std;
int main()
{
bool x = true;//定义一个布尔型变量x,初始值化为true
cout<<x<<endl;//显示变量x的值,true被显示为1
int y; //再定义1个int型变量
y=x;// 将布尔型变量x赋值给int型变量y,C++将自动转化类型,true被转换为1
cout<<y<<endl;//显示y的值,结果为1
x=5; //将int型变量5赋值给布尔型变量,5被转换为true,即非0转换为true,此时编译器会提示warning错误
cout<<x<<endl;//显示变量x的值,true显示被显示为1
return0;
}
在布尔型数据中,true和false是常量。除了赋值运算外,还可以对布尔类型的变量进行关系运算,或者是逻辑运算。
由关系运算符构成的表达式,就是关系表达式,关系表达式的作用就是比较两个数的大小,比较的结果是布尔类型,结果为true说明条件成立,为false说明条件不成立。
关系运算符 | 优先级 | 结合性 |
---|---|---|
大于(>) | 6 | 从左向右 |
大于等于(>=) | 6 | 从左向右 |
小于(<) | 6 | 从左向右 |
小于等于(<=) | 6 | 从左向右 |
等于(==) | 7 | 从左向右 |
不等于(!=) | 7 | 从左向右 |
逻辑运算符用于判断复合条件是否成立。结果为布尔类型。
逻辑运算符 | 优先级 | 运算规则 |
---|---|---|
与(&&) | 11 | 双目运算符,真真为真、否则都为假,相当于并取的意思 |
或(||) | 12 | 双目运算符,假假为假,否则都为真,相当于或的意思 |
非(!) | 2 | 单目运算符,非假即真,非真即假,相当于求反的意思 |
参与逻辑运算的操作数必须是布尔类型,否则将自动转换,其他类型转为布尔类型的规则是,0转为false,非0转为true。
算法中某些操作步骤,需要满足特定条件才能执行,比如求变量x的倒数,需要判断x不等于0是否成立,若成立进行算法运算,否则应提示错误信息。
句型:如果......,就......,否则,,,,,,
选择结构/分支结构:如果条件成立,则执行算法分支1,否则执行算法分支2
C++语言提供了2中选择语句句型:
使用方法:
if(表达式)
{语句1;}
else
{语句2;}
语法说明:
/*实例一:求一个数的倒数*/
#include <iostream>
using namespace std;
int main()
{
double x;
cout<<"请输入一个数值:"<<endl;
cin>>x;
if (x!=0) //判断条件
/*条件成立,执行以下语句,有3条语句,所以不需大括号括起来*/
{
double y;
y = 1/x;
cout<< "x的倒数为:"<<y<<endl;
}
else
cout<<"因为x的值等于0,0没有倒数"<<endl; //else只有1条语句,可以省略大括号
return 0;
}
C++语言将一对大括号括起来的语句称为一条复合语句。C++还要一种特殊的语句,空语句,是由单个;组成的,计算机在执行空语句时不会执行任何操作,空语句也没有任何实际的用途,只是在某些特殊的语法场合需要空语句。
/*实例二:判断一个年份是不是闰年*/
#include <iostream>
using namespace std;
int main()
{
int x;
cout<<"请输入一个年份:"<< endl;
cin>>x;
if ((x%100!=0 && x%4==0) || x%400==0) //复合条件判断语句,用括号括起来。
cout<<x<<"是闰年";
else
cout<<x<<"不是闰年";
return 0;
}
复合判断语句用在if后面,用括号括起来。可以多层嵌套。
/*求解符号函数*/
#include <iostream>
using namespace std;
int main()
{
float x; //要判断的数
cout<<"请输入一个实数:"<<endl;
cin>>x;
int a; //用来保存结果
if(x==0) //先判断0
cout<<"0没有符号,值为:"<<a;
/*复合语句判断x的值,并确定a的值,最后输出提示性语句和a*/
else
{
if(x<0) a=-1;
else a=1;
}
cout<<a<<endl;
return 0;
}
if_else可以多层嵌套,每个else自动的和上面最近的if配对,如果else配对错误,那么执行结果也是错误的。所以为了慎重起见,上层的if_else语句应对添加大括号,将下层的if_else语句括起来
良好的书写习惯可以提供代码的可读性,要合理利用空格、缩进、空行和注释,来区分语句的层次,说明语句的功能和用途。
if_else多层嵌套代码可读性低,C++还提供了一种更加直观简洁的写法if...else if_..._else,的书写方式,求解符号实例可以改造为:
#include <iostream>
using namespace std;
int main()
{
float x; //要判断的数
cout<<"请输入一个实数:"<<endl;
cin>>x;
int a; //用来保存结果
if(x==0) a=0;
else if(x>0) a=1;
else a=-1;
cout<<a<<endl;
return 0;
}
if-else if-else语法:
if(表达式1) 语句1;
else if(表达式2) 语句2;
......
else if(表达式n) 语句n;
else 语句n+1
#include <iostream>
using namespace std;
int main()
{
int x;
cout <<"请输入一个数字:"<< endl;
cin >> x;
if(x == 1) cout <<"Today is Monday!"<<endl;
else if (x==2) cout <<"Today is Tuesday!"<<endl;
else if (x==3) cout <<"Today is Thursday!"<<endl;
else if (x==4) cout <<"Today is Wednesday!"<<endl;
else if (x==5) cout <<"Today is Friday!"<<endl;
else if (x==6) cout <<"Today is Saturday!"<<endl;
else if (x==7) cout <<"Today is Sunday!"<<endl;
else cout<<"数值超出1-7的范围"<<endl;
return 0;
}
符号标识:由问号和冒号组成“?:”
在程序设计中,如果条件成立,则执行算法分支1,否则执行算法分支2,双分的if-else支结构,可以通过条件运算符来实现简单的分支结构。语法规则如下:
表达式1 ? 表达式1 : 表达式2
语法说明:
int a =5, b = 10, c;a>b ? a:b //这是一个条件表达式,结果为10,数据类型为int型
cout(a>b ? a:b); //显示表达式的结果
c = a>b ? a:b; //将结果赋值给int型变量c
实列:
#include <iostream>
using namespace std;
int main(){
int a=5,b=10,c;
a>b ? a:b;
cout<<c<<endl;
c= (a>b ? a:b);
return 0;
}
分支结构算法中,有一类特殊的算法,某一表达式结果,可分成若干种情况,每一种情况,只写一种算法分支,C++语言提供了switch-case结果来描述这种多分支结果。语法形式比if-else更加简洁直观。
语法:
switch(表达式)
{
case 常量表达式1:语句1;
case 常量表达式2:语句2;
......
case 常量表达式n:语句n;
default:语句n+1;
}
说明:
实例一:有break语句跳出比对的情况
/*有break语句的情况*/
#include <iostream>
using namespace std;
int main(){
int x;
cout<<"请输入一个标识星期几的数值:";
cin>>x;
switch (x) //下列的case语句会根据switch中x的值进行比较
{
case 1:cout<<"Today is Monday!"<<endl ; break;
case 2:cout<<"Today is Tuesday!"<<endl ; break;
case 3:cout<<"Today is Thursday!"<<endl ; break;
case 4:cout<<"Today is Wednesday!"<<endl ; break;
case 5:cout<<"Today is Friday!"<<endl ; break;
case 6:cout<<"Today is Saturday!"<<endl ; break;
case 7:cout<<"Today is Sunday!"<<endl ; break;
default: cout<<"input error"<<endl;
}
//每个case语句只要是执行了cout语句,程序功能就已经完成
//使用break语句中途跳出switch语句,继续执行switch语句的下一条语句,即return语句
return 0;
}
实例二:无break的情况
#include <iostream>
using namespace std;
int main(){
int mouth;
cout<<"请输入一个标识月份的数值:";
cin>>mouth; switch (mouth)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:cout<<"这个月是大月,有31天"<<endl; break;
case 4:
case 6:
case 9:
case 11:cout<<"这个月是小月,只有30天"<<endl; break;
case 2:cout<<"2月天数为28天,闰年29天"<<endl; break;
default: cout<<"input error"<<endl;
}
return 0;
}
若多个case的语句一样,可以共用语句。
有些算法,在满足特定条件下,将重复执行某些操作步骤,这种结构称之为循环结构,循环结构就是在条件成立时,重复执行某个操作,否则结束循环。
循环4要素:循环变量、初始值、循环条件、循环体
循环语句:while语句、do—while语句、for语句
实例分析:求奇数数列1,3,5.......2n-1的前N项累加和,公式,奇数数列前N项的和,是一个重复累积的过程,累加起点就是n=1时,累加条件是nN,直到这个条件不成立。
语法:
while(表达式)
语句
/*求奇数数列1,3,5.......2n-1的前N项累加和*/
#include <iostream>
using namespace std;
int main(){
int N,sum=0,n=1; //定义变量,并将用于保存结果的sum初始化为0,开始的n初始化为1
cout<<"请输入计算的值:";
cin>>N; //获取前N项
while (n<=N)
{
sum += 2*n-1; // 等价于sum=sum+2*n-1,
n++; //执行完上一条语句,将n自增1。该条语句用于跳出循环,使得循环条件n<=N趋于false
}
cout<<"前"<<N<<"项的累积结果为:"<<sum<<endl; //跳出循环后,执行本条语句,显示变量sum
return 0;
}
do—while语句是先执行循环体,在判断条件。语法如下:
do
语句
while(表达式);
/*求奇数数列1,3,5.......2n-1的前N项累加和*/
#include <iostream>
using namespace std;
int main(){
int N,sum=0,n=1;
cout<<"请输入计算的值:";
cin>>N;
do
{
sum += 2*n-1;
n++;
}
while (n<=N);
cout<<"前"<<N<<"项的累积结果为:"<<sum<<endl;
return 0;
}
for语句语法:
for(表达式1;表达式2;表达式3)
语句
/*求奇数数列1,3,5.......2n-1的前N项累加和*/
#include <iostream>
using namespace std;
int main(){
int N,n,sum=0;
cout<<"请输入计算的值:";
cin>>N;
for(n=1;n<=N;n++) //集中用3个表达式来指定n=1,循环条件n<=N,以及修改循环条件中的变量N,使得循环趋向于false
sum += 2*n-1; //表达式n<=N为true时执行的语句
cout<<"前"<<N<<"项的累积结果为:"<<sum<<endl;
return 0;
}
逗号运算符,可以将多个表达式链接在一起,构成一个复合的逗号表达式,
表达式1, 表达式2, ......, 表达式n
实例说明:
int a,b,c;
a=5, b=10, c=a+b; //依次执行,所以a=5, b=10, c=15,计算机会将最后的表达式计算结果(c=a+b)作为该表达式的结果,故结果为15
cout<<(a,b,c); //显示逗号表达式的结果,结果为15
编写程序时,可以将多个表达式语句用逗号运算符连接起来,构成一个长的表达式语句,使得程序更加紧凑,利用逗号运算符改写求奇数列前N项的累积和程序。
/*求奇数数列1,3,5.......2n-1的前N项累加和*/
#include <iostream>using namespace std;
int main(){
int N,n,sum;
cout<<"请输入计算的值:";
cin>>N;
for(n=1,sum=0;n<=N;n++) //集中用3个表达式来指定n=1,循环条件n<=N,以及修改循环条件中的变量N,使得循环趋向于false
sum += 2*n-1; //表达式n<=N为true时执行的语句
cout<<"前"<<N<<"项的累积结果为:"<<sum<<endl;
return 0;
}
计算机通常是按照语句的书写顺序执行程序的,而某些语句,会造成执行顺序的跳转,例如选择语句和循环语句,造成程序执行顺序跳转的语句,统称为控制语句。
break语句
break语句的作用就是跳出整个循环,例如,我们设计一个可以求圆的面积和周长的程序,我们一直输入半径,程序就一直计算,而不必每次都打开程序。
#include <iostream>
using namespace std;
int main(){
const int Pi=3.14;
double r,s,c;
while(true) //使用关键字true将while设置为死循环,如果不跳出循环的话,while下的语句块会一直执行。
{
cout<<"请输入圆的半径:";
cin>>r;
s = r*r*Pi;
c = 2*r*Pi;
if(r<0) break; //break的作用就是跳出整个循环
cout<<"一个半径为:"<<r<<"的圆的面积="<<s<<"周长等于"<<c<<endl;
}
return 0;
}
continue
continue 的作用是跳出当前循环,中途返回,继续执行下一个循环。比如设计一个程序,能显示一个范围内,能被3整除的数。
#include <iostream>
using namespace std;
int main(){
int a,b;
cout<<"请输入取值范围,小的在前,大的在后:";
cin>>a>>b;
for(a,b;a<=b;a++)
{ if (a%3!=0) continue; //如果n不能被3整除,则执行continue,跳过此次判断,执行下一个循环语句。
cout<<a<<","; //只返回能被3整除的数。其他的数都被continue跳出时过略掉了。
}
return 0;
}
continue只能在循环语句中使用,而break还能够在switch-case选择语句中使用。
程序设计中,算法应当时可实现的,算法应当能被计算机执行,算法应当完成某种功能,具有使用价值,因此,我们设计的算法应对具有以下5个特性:
如何评判一个算法的优劣,是通过算发杂程度和内存占用量,这是评价一个算法优劣的基本标准。
算法复杂度:决定了计算执行该算法所续的时间,完成相同的功能计算复杂度越小,算法执行速度越快,算法就越好。
实列:判断一个数是否是素数
#include <iostream>
using namespace std;
int main(){
int a;
cout<<"请输入一个正整数:";
cin>>a;
bool yes_no = true;
for(int n=2; n<a; n++)
{
if(a%n==0)
{
yes_no=false;break;
}
}
if(yes_no==true)cout<<a<<"是素数";
else cout<<a<<"不是素数";
return 0;
}
在上述实例中,a只需检查能否被n~a/2以内的数整除,就可以判断a是否是素数,降低循环的次数,就可以降低程序的算法复杂程度,从而优化程序。保证正确性的情况下, 程序的执行速度越快越好。
内存占用量
内存占用量用于评估计算机执行算法时,所需空间的大小,完成相同的功能,内存占用量空间越小,那么算法就越好。
#include <iostream>
using namespace std;
int main(){
double a, b, c;
double sum;
cout<<"请依次输入3个人的成绩:";
cin>>a;cin>>b;cin>>c;
sum= (a+b+c)/3;
cout<<"平均成绩为:"<<sum<<endl;
return 0;
}
在该算法中,定义了4个double型变量,每个变量占用8个字节,因此总共占用了32个字节,成绩的取值范围是0-100,使用单精度浮点型float类型完全能够满足需求,每个float型变量只占用4个字节,总共占用16个字节,同时减小变量的定义数量,也可以减少不必要的内存开销。对上述程序进行完善:
#include <iostream>
using namespace std;
int main(){
float source;
float sum = 0;
cout<<"请依次输入3个人的成绩:";
cin>>source;sum += source;
cin>>source;sum += source;
cin>>source;sum += source;
cout<<"平均成绩为:"<<sum/3<<endl;
return 0;
}
通过对程序算法的优化,新程序内存开销仅占用8个字节。
最后的实例:求反正切(arctan)函数的算法设计,计算机只能进行算术运算,关系运算,逻辑运行等基本运算,不能直接运行对数函数这一类的复杂运算,此类复杂运算,需要分解成基本运算进行求解。
公式化解为:,其中记
分子:
分母:
那么: