510 likes | 665 Views
三、 程序的三种基本结构. 3.1 顺序结构 3.2 分支结构 ( 里面含部分自主学习 ) 3.3 循环结构 ( 里面含部分自主学习 ) 3.4 使用 string 3.5 其他应用. 木纹背景的资料属自主学习的内容. 3.1 顺序结构 为了提高程序设计的质量和效率, C 语言中经常采用结构化程序设计方法。当然,面向对象程序设计方法在 C++ 中用得更为常见。不过两者并不矛盾,因为在面向对象程序设计方法中也一定包含了结构化程序设计方法,因此,作为基础,必须熟练掌握结构化程序设计的方法。
E N D
三、 程序的三种基本结构 3.1 顺序结构 3.2 分支结构(里面含部分自主学习) 3.3 循环结构(里面含部分自主学习) 3.4 使用string 3.5 其他应用 木纹背景的资料属自主学习的内容
3.1 顺序结构 为了提高程序设计的质量和效率, C语言中经常采用结构化程序设计方法。当然,面向对象程序设计方法在C++中用得更为常见。不过两者并不矛盾,因为在面向对象程序设计方法中也一定包含了结构化程序设计方法,因此,作为基础,必须熟练掌握结构化程序设计的方法。 结构化程序由若干个基本结构组成。每一个基本结构可以包含 一个或若干个语句。有三种基本结构. 采用流程图可以较好地描述算法的思路。 当语句之间是顺序执行的关系时,就是顺序结构,这也是最简单的结构。
3.2 分支结构 又称选择结构,典型的流程图如下:
分支结构的相关知识 3.2.1 关系运算符和关系表达式 3.2.2 逻辑运算符和逻辑表达式 3.2.3if语句 3.2.4switch语句(自主学习) 3.2.5 条件运算符
3.2.1 关系运算符和关系表达式 1)关系运算符及其优先次序 关系运算是逻辑运算中比较简单的一种。所谓“关系运算”实际上是“比较运算”。将两个值进行比较,判断其比较的结果是否符合给定的条件。比较的结果是一个逻辑值(true,false)。 6种关系运算符的优先次序如下: < 、<= 、 > 、>= , == 、!= 其中,前4个优先级相同,后2个优先级相同,前4种高于后2种。关系运算符的优先级低于算术运算符,高于赋值运算符。 2)关系表达式: 用关系运算符将两个表达式连接的表达式。关系表达式的值也是一个逻辑值(true,false)。 一般形式为:表达式 关系运算符 表达式
3.2.2 逻辑运算符和逻辑表达式 1)3种逻辑运算符及其优先次序 !,&&,|| &&、||为双目运算符,左结合; !为单目运算符,右结合。 优先级如右图: 2)逻辑表达式 用逻辑运算符将关系表达式或逻辑量连接起来的式子就是逻辑表达式。表达式的值也是一个逻辑值(true,false)。 逻辑表达式的一般形式为: 表达式 逻辑运算符 表达式
3.2.3if 语句 共有3种形式的if语句 1) if(表达式) 语句 例如: if(x>y) { cout<<“hello”; } 这种if语句的执行过程见图。
2)if(表达式) 语句1 else 语句2 例如: if (x>y) { cout<<“first condition”; } else { cout<<“second condition”; }
例如: if(number>500) { cost=0.15; } else if(number>300) { cost=0.10; } else if(number>100) { cost=0.075; } elseif(number>50) { cost=0.05; } else { cost=0; } 3) if(表达式1) 语句1 else if(表达式2) 语句2 else if(表达式3) 语句3 … else if(表达式m) 语句m else 语句n
4) 在使用if语句应注意的问题: • if之后均为表达式。该表达式通常是逻辑表达式或关系表达式,但也可以是其它表达式,如赋值表达式等,甚至也可以是一个变量。 • 在if语句中,条件判断表达式必须用括号括起来,在语句之后必须加分号。 • 在if语句中的内嵌语句为多个语句时,必须把这多个语句用{}括起来组成一个复合语句。但要注意的是在}之后不能再加分号。 • if语句可以嵌套,流程图见后页。
例:输入三角形的3个边长,判断能否构成三角形例:输入三角形的3个边长,判断能否构成三角形 #include <iostream> #include <cmath> using namespace std; int main() { float a,b,c; cin>>a>>b>>c; if (a+b>c && a+c>b && b+c>a) { cout<<"Yes“<<endl; } else { cout<<"No“<<endl; } return 0; }
例:输入3个各不相同的数,输出最大、最小值例:输入3个各不相同的数,输出最大、最小值 #include <iostream> using namespace std; int main() { float a, b, c, maxVal, minVal; cin>>a>>b>>c; if (a>b && a>c) maxVal=a; else if (b>a && b>c) maxVal=b; else if (c>a && c>b) maxVal=c ; if (a<b && a<c) minVal=a; else if (b<a && b<c) minVal=b; else if (c<a && c<b) minVal=c; cout<<“Max, Min :”<<maxVal<<“,”<<minVal<<endl; return 0; }
3.2.4switch语句(自主学习) switch语句是多分支选择语句。用来实现多分支选择结构。if语句只有两个分支可供选择,而实际问题中常常需要用到多分支的选择。 例如,学生成绩分类(90分以上为‘a’等,80~89分为‘b’等,70~79分为‘c’等……);人口统计分类(按年龄分为老、中、青、少、儿童);工资统计分类;银行存款分类……。 语法格式如下: switch(表达式) { case 常量表达式1:语句1 case 常量表达式2:语句2 … case 常量表达式n:语句n default:语句n+1 }
例如,要求按照考试成绩的等级打印出百分制分数段,可以用Switch语句实现:例如,要求按照考试成绩的等级打印出百分制分数段,可以用Switch语句实现: switch(grade) { case‘A'∶ cout<<"85~100\n";break; case‘B'∶ cout<<"70~84\n"; break; case‘C'∶ cout<<"60~69\n"; break; case‘D'∶ cout<< "<60\n"; break; default∶ cout<<"error\n"; }
说明 (1)有无break语句的区别。 (2)在case后的各常量表达式的值不能相同,否则会出错。 (3)各case和default子句的先后顺序可以调换。 (4)在case后,允许有多个语句,可以不用{}括起来。 (5)default子句可以省略不用。 (6)多个case可以共用一组执行语句。 (7)表达式允许为任何类型。
3.2.5 条件运算符(了解即可) 若if语句中,在表达式为“真”和“假”时,且都只执行一个赋值语句给同一个变量赋值时,可以用简单的条件运算符来处理。例如,若有以下if语句: if (a>b) max=a; else max=b; 可以用下面的条件运算符来处理: max=(a>b)?a∶b; 其中“(a>b)?a∶b”是一个“条件表达式”。它是这样执行的:如果(a>b)条件为真,则条件表达式取值a,否则取值b。
3.3 循环结构 • 3.3.1 while • 3.3.2 do while(自主学习) • 3.3.3 for • 3.3.4 break和continue • 3.3.5 示例
3.3.1 while while语句用来实现“当型”循环结构。其一般形式如下: while (表达式) 语句
例: 求sum=1+2+3+…+100 int main( ) { int i=1,sum=0; while(i<=100) { sum=sum+i; i++; } cout<<sum<<endl; return 0; }
3.3.2 do while do while语句的特点是先执行循环体,然后判断循环条件是否成立。一般形式为 do 循环体语句 while (表达式);
例: 求sum=1+2+3+…+100 int main() { int i=1,sum=0; do { sum=sum+i; i++; }while (i<=100); cout<<sum<<endl; return 0; }
3.3.3 for for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况,它完全可以代替while语句。一般形式为: for(表达式1;表达式2;表达式3) 语句
它的执行过程如下: (1) 先求解表达式1。 (2) 求解表达式2,若其值为真,则执行for语句中指定的内嵌语句,然后执行下面第(3)步。若为假,则结束循环。 (3) 求解表达式3。 (4) 转回上面第(2)步骤继续执行。 for语句最简单的应用形式形式: for(循环变量赋初值;循环条件;循环变量增值) 语句 例如: for(int i=1; i<=100; i++) sum=sum+i;
int main() { int sum=0; for( int i=1;i<=100;i++) { sum=sum+i; } cout<<sum<<endl; return 0; } int main() { int i,sum=0; for( i=1;i<=100;i++) { sum=sum+i; } cout<<sum<<endl; return 0; } 例: 求sum=1+2+3+…+100
3.3.4 break和continue break语句在前面已经介绍过,可以使流程跳出Switch结构,继续执行Switch语句下面的一个语句。实际上,break语句还可以用来从循环体内跳出循环体,即提前结束循环,接着执行循环下面的语句。 continue的作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。
continue语句和break语句的区别是:continue语句只结束本次循环,而不是终止整个循环的执行。而break语句则是结束整个循环过程,不再判断执行循环的条件是否成立。continue语句和break语句的区别是:continue语句只结束本次循环,而不是终止整个循环的执行。而break语句则是结束整个循环过程,不再判断执行循环的条件是否成立。 注意: A、break语句对if-else的条件语句不起作用。 B、在多层循环中, 一个break语句只向外跳一层。
3.3.5 示例: 例:多项式如下:π/4 =1 - 1/3 + 1/5 - 1/7 + 1/9 ...计算的项数n由键盘输入,求π。结果保留2位小数。 #include <iomanip> int main(){ int n, sign=1; double sum=0.0; cin>>n; for(int i=1; i<=n; i+=2) { sum = sum + sign*1.0/i; sign = -sign; } // 设置浮点数的小数个数2位 cout<<fixed<<setprecision(2)<<4*sum<<endl; return 0; }
例:统计给定的n个整数中,负数、零和正数的个数。例:统计给定的n个整数中,负数、零和正数的个数。 输入第一个数是整数n(n<100),表示需要统计的数值的个数,然后是n个整数,分别输出给定的数据中负数、零和正数的个数。 int main(){ int n,x; cin>>n; int zero=0, positive=0, negative=0; for(int i=0; i<n; i++){ cin>>x; if (x>0) positive++; else if (x<0) negative++; else zero++; } cout<<negative<<" "<<zero<<" "<<positive<<endl; return 0; }
例:古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为: 1+2+4+5+10+11+20+22+44+55+110=284。 而284的所有真约数为1、2、4、71、 142,加起来恰好为220。人们对这样的数感到很惊奇,并称之为亲和数。一般地讲,如果两个数中任何一个数都是另一个数的真约数之和,则这两个数就是亲和数。编程,判断给定的两个数是否是亲和数。 Input 输入数据包含两个整数A,B; Output 如果A和B是亲和数的话输出YES,否则输出NO。
int main(){ int a, b, sumA=0, sumB=0; cin>>a>>b; for (int i=1; i<a; i++){ if (a%i==0) sumA+=i; } for(int j=1; j<sumb; j++){ if (b%j==0) sumB+=j; } if ( sumA==b && sumB==a) cout<<"YES\n"; else cout<<"NO\n"; return 0; }
3.4 使用string 3.4.1 基本运算 3.4.2 示例
3.4.1 基本运算 #include<string> // 包含头文件 声明变量及初始化: string s1,s2,s3 = "Hello"; 赋值: s2=“World”; 串加法运算 s1=s2+s3; 串比较运算 if(s2>s3) cout<<“Bigger”<<endl; 输出 cout<<s3<<endl; 处理串成员(字符)的方法 s[序号](其中,序号的范围,0~length-1)
输入string的方式: • cin>>的读入方式总是将前导的空格(所谓空格,即包括空格、回车、水平或垂直制表符等)滤掉,将单词读入,在遇到空格时结束本次输入 • getline总是将行末的回车符滤掉,将其整行输入 对字串”Hello, How are you?”的两种输入方式 //方法1 string s; while(cin>>s) cout<<s<<”“; cout<<endl; //方法2(优先考虑本方法) string s; getline(cin, s); cout<<s<<endl;
例:判断回文串 (HLOJ 1111) int main(){ int total; // 表示测试总数 cin>>total; for(int i=1; i<=total; i++){ string s; cin>>s; bool flag=true; // 存放结果 len=s.size(); // s.size()表示串s的长度 for(int j=0; j<len/2; j++) { if (s[j] != s[len-1-j]) { // 判断字符的范围 flag=false; break; } } if(flag==true) cout<<“YES”<<endl; else cout<<“NO”<<endl; } return 0; }
例:对于输入的每个字符串,查找其中的最大字母,在该字母后面插入字符串“(max)”。 (HLOJ1139) int main(){ while(true){ string s; if((cin>>s)==NULL) break; // 离开测试的条件(必要) //或者 if(!(cin>>s)) break; // 也可使用本方法 char maxchar=s[0]; for(int i=1; i<s.size(); i++) { // 寻找最大字符 if(s[i]>maxchar) maxchar=s[i]; } for(int j=0; j<s.size(); j++) { // 按要求输出 cout<<s[j]; if(s[j]==maxchar) cout<<"(max)"; } cout<<endl; } return 0; }
(HLOJ1139)的另一种方式: int main(){ string s; while(cin>>s){ char maxchar=s[0]; for(int i=1; i<s.size(); i++){ // 寻找最大字符 if(s[i]>maxchar) maxchar=s[i]; } for(int j=0; j<s.size(); j++){ // 按要求输出 cout<<s[j]; if(s[j]==maxchar) cout<<"(max)"; } cout<<endl; } return 0; }
例:输入一个只包含空格和小写字母的英文句子,将每个单词的第一个字母改成大写首字母。 (HDOJ2026) int main(){ while(true){ string s; if (!getline(cin,s)) break; // 离开测试的条件 s[0]=s[0]-‘a’+‘A’; // 处理首字母 for(int i=1; i<s.size(); i++) { // 小写转大写 if(s[i-1]==' ') s[i]=s[i] - 'a' + 'A'; } cout<<s<<endl; } return 0; }
(HDOJ2026)的另一种方式: int main(){ string s; while(getline(cin,s)) { // 离开测试的条件 s[0]=s[0]-‘a’+‘A’; // 处理首字母 for(int i=1; i<s.size(); i++) { // 小写转大写 if(s[i-1]==' ') s[i]=s[i] - 'a' + 'A'; } cout<<s<<endl; } return 0; }
3.5 其他应用 3.5.1 简单字符图形的双重循环 3.5.2 判断素数 3.5.3 百鸡问题 3.5.4 最大公约数
3.5.1 简单字符图形的双重循环 M MM MMM MMMM MMMMM MMMMMM MMMMMMM MMMMMMMM MMMMMMMMM MMMMMMMMMM 分析方法: 该图形一共10行,每一行增加一个字符,所以,应循环10次,每次输出一行,其循环模式为: for(int i=1; i<=10; ++i) { 输出第i行(循环) 换行 } • 行 i M的个数 • 1 1 1 • 2 2 2 • 3 3 3 • 4 4 4 • ... • 10 10 10 for(int i=1; i<=10; ++i) { for(int j=1; j<=i; ++j) cout<<”M”; cout<<endl; }
3.5.2 判断素数:(利用数学定律) m=i×j 假定i≤j, 则 i2≤i×j=m≤j2 即 i2≤m≤j2 即 i≤√m≤j int m; cin>>m; bool isPrime=true; int sqm=(int)sqrt(m*1.0); for(int i=2; i<=sqm; i++) { if(m%i==0) { isPrime= false; break; } }
3.5.3 百鸡问题 本问题记载于中国古代约5-6世纪成书的《张邱建算经》中,是原书卷下第38题,也是全书的最后一题:「今有鸡翁一,值钱伍;鸡母一,值钱三;鸡鶵(雏 )三,值钱一。凡百钱买鸡百只,问鸡翁、母、鶵各几何?答曰:鸡翁四,值钱二十;鸡母十八,值钱五十四;鸡鶵七十八,值钱二十六。又答:鸡翁八,值钱四十;鸡 母十一,值钱三十三,鸡鶵八十一,值钱二十七。又答:鸡翁十二,值钱六十;鸡母四、值钱十二;鸡鶵八十 四,值钱二十八。」 该问题导致三元不定方程组,其重要之处在于开创「一问多答」的先例,这是过去中国古算书中所没有的。 100元钱买100只鸡, 大公鸡5元1只,母鸡3元1只,小鸡1元3只。 问公鸡,母鸡,小鸡各多少只?
分析:把三种鸡的只数分别设为未知数x、y、z,然后利用总只数、总钱数两个条件,列出两个方程,根据鸡的只数必须取整数的要求,一步一步推出各种鸡的只数。分析:把三种鸡的只数分别设为未知数x、y、z,然后利用总只数、总钱数两个条件,列出两个方程,根据鸡的只数必须取整数的要求,一步一步推出各种鸡的只数。 解:设大公鸡x只,母鸡y只,小鸡z只。根据题意,得
方法一:int x,y,z; //cock, hen, chick;for(x=1; x<=100/5; x++){for(y=1; y<=100/3; y++) {for(z=1; z<=100; z++) { if(x+y+z==100 && 5*x+3*y+z/3==100 && z%3==0) { cout<<x<<“,”<<y<<“,”<<z<<endl; } }
方法二:int x,y,z; //cock, hen, chick;for(x=1; x<=100/5; x++){for(y=1; y<=100/3; y++) { z=100-x-y; if(5*x+3*y+z/3==100 && z%3==0) {cout<<x<<“,”<<y<<“,”<<z<<endl; } } 方法三、四……(请上网查找或自己思考)
3.5.4 最大公约数 方法一: 直接利用性质求解(略)
方法二(欧几里德Euclid算法): 欧几里德算法又称辗转相除法,用于计算两个整数a, b的最大公约数。其计算原理依赖于下面的定理:gcd(a, b) = gcd(b, a mod b) 证明:a可以表示成a = kb + r,则r = a mod b 1) 假设d是a,b的一个公约数,则有d|a, d|b, 而r = a - kb,因此d|r ,因此d是(b,a mod b)的公约数 2) 假设d 是(b,a mod b)的公约数,则 d|b , d|r , 但是a = kb +r ,因此d也是(a,b)的公约数 因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。