程序设计与算法 | (5) 分支与循环

本专栏主要基于北大郭炜老师的程序设计与算法系列课程进行整理,包括课程笔记和OJ作业。该系列课程有三部分: (一) C语言程序设计;(二) 算法基础;(三) C++面向对象程序设计

(一) C语言程序设计 课程链接

1. 条件分支结构之if语句

有时,并非所有的程序语句都要被顺序执行到,会希望满足某种 条件就执行这部分语句,满足另一条件就执行另一部分语句。这就需 要“条件分支结构”

if语句

在这里插入图片描述

  • 依次计算表达式1、表达式2…只要碰到一个表达式i为真,则执行语句组i(前面为假的表达式对应的语句组不会被执行),后面的表达式不再计算,后面的语句组也都不会被执行。
  • 若所有表达式都为假,则执行语句组n
  • 可以没有 else if,也可以没有 else,也可以都没有
    在这里插入图片描述
  • 如果“语句组”只有一条语句,可以不用{ }
    在这里插入图片描述
例题

写一个判断整数奇偶性的程序,要求输入一个整数,如果是奇数,就输出“It’s odd.”,如果是偶数,就输出“It’s even.”。

#include <iostream>
using namespace std;
int main() 
{
	int n; 
	scanf("%d",&n); 
	if( n % 2 == 1)
	   printf("It's odd.\n") ;
	else
	   printf("It's even.\n") ; 
	return 0;
}
#include <iostream>
using namespace std;
int main() 
{
	int n; 
	scanf("%d",&n); 
	if( n % 2) //取余2非0 则为奇数,C++中非0整数为true
	   printf("It's odd.\n") ;
	else
	   printf("It's even.\n") ; 
	return 0;
}
if语句嵌套

在一条if语句的某个分支(语句组)里,还可以再写if语句。

#include <iostream> 
using namespace std; 
int main()
{
	int a; 
	scanf("%d",&a); 
	if( a > 0)
		if ( a % 2 )
	    	cout << "good";
	else //这个else到底和哪个if配对? 
		cout << "bad";
	return 0; 
} //输入-1,输出?

注意在上面的c++代码里不要看对齐,else总是和离他最近的if配对。实际情况如下:

#include <iostream> 
using namespace std; 
int main()
{
	int a;
	scanf("%d",&a);
	if( a > 0) //if-else语句整体是一条语句 所以此处可以不加{}
		if ( a % 2 )
			cout << "good";
		else
			cout << "bad"; 
	return 0;
} //输入-1, 程序无输出!!!

可以使用{},改变if-else的配对,下面的代码中加了{}后,else就可以与第一个if配对了:

int main() {
	int a; 
	scanf("%d",&a); 
	if( a > 0) {
		if ( a % 2 )
	    	cout << "good";
	}
	else
		cout << "bad";
	return 0; 
} //输入-1,输出 bad

请写一个程序,该程序输入一个年份,根据该年份是否是建国整十周年、建党整 十周年以及是否是闰年给出不同的输出。

 
#include <iostream>
using namespace std;
int main()
{
	int year; 
	scanf("%d",& year); 
	if( year <= 0)
		printf("Illegal year.\n") ;
	else {
		printf("Legal year.\n");
		if( year > 1949 && (year - 1949) % 10 == 0 ) //建国整10周年
			printf("Luky year.\n");
		else if( year > 1921 && !((year - 1921) % 10)) //建党整10周年
			printf("Good year.\n");
		else if( year % 4 == 0 && year % 100 || year % 400 == 0 ) //整除4且不整除100或整除400
			printf("Leap year\n"); //闰年 
		else 
			printf("Common year.\n");
	}
	return 0;
}
if语句常见错误
int a = 0;
if( a = 0 ) //a = 0的值是0。0为假
	printf("hello");
if( a = 5 ) // a = 5的值是5。非0为真
    printf("Hi");

输出 Hi。
注意=是赋值,==是判断相等。

互相矛盾的多个条件,如果确实只希望执行其中一个分支,应该用if和多个else if,而不要写多个if

int a = 0;
if( a >=0 && a < 5 )
    a = 8;
else if( a >= 5 && a < 10 )
	cout << "hello";
else if( a > 10 && a < 20)
	..... 
else
	.....

此时不会输出hello,只会执行一个分支。

错误写法:

int a = 0;
if( a >=0 && a < 5 )
   a = 8;
if( a >= 5 && a < 10 )
   cout << "hello";
if( a > 10 && a < 20)
 	.....
if( a >= 20)
	.....

此时会输出hello, 会执行多个分支。

2. 条件分支结构之switch语句

switch语句
if( n % 5 == 0 ) { 
	......
}
else if(n % 5 == 1 ) {
	...... 
}
else if( n % 5 == 2 ) {
    ......
}
else if( n % 5 == 3 ) {
	...... 
}
else {
	......
}
  • 太多的else if 不方便
  • n % 5多次计算,浪费
switch(表达式) { //表达式的值 必须是整数类型(int,char ......) 
case 常量表达式1: //常量表达式必须是整数类型的常量(int,char...)
	语句组1
	break;
case 常量表达式2: 
	语句组2
	break; 
......
case 常量表达式n: 
	语句组n
    break;
default:
	语句组n+1
}

“表达式”(表达式只计算一次即可)的值等于哪个“常量表达式”, 就执行相应的语句组。都不相等,则执行 default的语句组。也可以没有default分支**“常量表达式” 里面不能包含变量**!

请写一个程序,接受一个整数作为输入,如果输入1,则输出“Monday” ,输入2,则输出“Tuesday”…输入7,则输出“Sunday”,输入其他数,则输出“Illegal”。

 
#include <iostream>
using namespace std;
int main()
{
	int n; 
	scanf("%d",& n); 
	switch(n) {
		case 1:
			printf("Monday");
            break;
        case 2:
            printf("Tuesday");
            break;
        case 3:
            printf("Wednesday");
            break;
        case 4:
			printf("Thursday"); 
			break;
		case 5:
        	printf("Friday");
        	break;
		case 6:
       		printf("Saturday");
        	break;
		case 7:
       		printf("Sunday");
        	break;
		default:
			printf("Illegal"); 
	}
	return 0;
}

switch语句在进入某个case分支后,会一直执行到第一个碰到的“break;” ,即使这个“break;”是在后面的case分支里面。如果没有碰到“break;”,则会向下一直执行到switch语句末尾的“}”,包括“default:”部分的语句组也会被执行。

#include <iostream>
using namespace std;
int main()
{
	int n; 
	scanf("%d",&n); 
	switch(n%6) {
        case 0:
        	printf( "case 0" );
			break;
		case 1:
             printf( "case 1" );
        case 2:
        case 3:
             printf( "case 2 or 3" );
             break;
        case 4:
             printf( "case 4" );
             break;
	}
	return 0; 
}

在这里插入图片描述

3. 循环结构之for循环

for循环
for( 表达式1 ;表达式2;表达式3){ 
	语句组
}

1)计算“表达式1”。
2)计算“表达式2”,若其值为true,则执行“{ }”中 的语句组,然后转到3);若为false,则不再执行“{}” 中的语句组,for语句结束,转到5)。
3)计算“表达式3”。
4)转到2)。
5) 从for语句后面继续往下执行程序。

一般用于将某段代码(语句组)重复执行若干次!!!
在这里插入图片描述

  • 连续输出26个字母
int i; //循环控制变量
for(i=0;i<26;i++){
	cout<<char('a'+i); //'a'+i为字母ASCII码 然后再用char()强制转换为char类型
}

for(int i=0;i<26;i++) //语句组里只有一条语句就可以不用写”{ }”
	printf("%c",'a'+i);
  • 循环控制变量定义在"表达式1"中,则其只在for语句内部起作用,可以不用担心循环控制变量重名:
int i = 5;
for(int i = 0;i < 26; ++i )
	cout << char('a'+i );
cout << endl;
for(int i = 0;i < 26; i+=2 ){ //循环控制变量并非每次只能加1
    cout << char('A'+i ) ;
 }
cout << endl;
cout << i; //此处的i和for里面的i无关

在这里插入图片描述

  • for循环结构里的“表达式1”和“表达式3”都可以是用逗号连接的若干个表达式。
for(int i= 15, j = 0; i > j; i-=2 ,j+= 3) 
	cout << i << "," << j << endl;
  • 写一个程序,输入一个正整数n,从小到大输出它的所有因子
#include <iostream> 
using namespace std; 
int main()
{
	int n;
	cin >> n;
	for( int i = 1;i <= n; ++i)
		if( n % i == 0 )
			cout << i << endl;
	return 0;
}
  • 写一个程序,输入一个正整数n,从大到小输出它的所有因子
#include <iostream> 
using namespace std; 
int main()
{
	int n;
	cin >> n;
	for( int i = n;i >= 1; --i)
		if( n % i == 0 )
			cout << i << endl;
return 0;
}
嵌套for循环

for循环可以嵌套,形成多重for循环。

for(int i = 0;i < n; ++ i) {
        ......
		for(int j = 0; j < m; ++j ) {
			...... //内重循环的执行次数一共是n×m次
		}
		...... 
}
  • 给定正整数n和m,在1至n这n个数中,取出两个不同(与顺序无关)的数,使得其和是m的因子,问有多少种不同的取法。
    思路:穷举1-n这n个数中取两个数的所有取法,对每一种取法,判断其和是不是m 的因子.
    穷举的办法:
    第一个数取1,第二个数分别取2,3,…n
    第一个数取2, 第二个数分别取3,4,…n

    第一个数取n-2,第二个数分别取n-1,n
    第一个数取n-1,第二个数取n
#include <iostream> 
using namespace std; 
int main()
{
	int n,m;
	int total = 0; //取法总数
	cin >> n >> m;
	for( int i = 1; i < n; ++i ) {//取第一个数,共n-1种取法
		for( int j = i + 1; j <= n; ++j ) //第二个数要比第一个数大,以免取法重复
			if(m%(i+j)==0)
				++total;
	}
	cout << total; 
	return 0;
}

for 语句括号里面的“表达式1”,“表达式2”,“表达式3”任何一个都可以不写,甚至可以全都不写,但是“;”必须保留。

for( ; i < 100; ++ i ) //假设i在for前已经有合理值
	cout << i ;
	
for( ; ; )
	cout << "hello" <<endl; //永远不停输出 hello

可以用 break 语句从 for( ; ;)死循环中跳出.

4. 循环结构之while循环、do…while循环

while循环

并非到达指定次数,而是满足某条件时即停止循环,则适合用while语句来实现循环:

while(表达式){
	语句组
}
  1. 判断“表达式”是否为真,如果不为真,则转4)
  2. 执行“语句组”
  3. 转1)
  4. while语句结束,继续执行while语句后面的语句。
while(true){
	语句组
} //死循环,可以用break跳出
  • 输入若干个(至少1个)不超过100的正整数,输出其中的最大值、最小值以及所有数的和。输入的最后一个数是0,标志着输入结束。
#include <iostream>
using namespace std;
int main() 
{
	int sum = 0, maxN = 0, minN = 200,n; //初始化最大值为最小,初始化最小值为最大
    cin >> n;
    while( n ){
    	if( n > maxN) 
    		maxN = n;
    	if( n < minN) 
    		 minN = n;
    	sum += n;
		cin >> n;
	}
	cout << maxN << " " << minN << " " << sum; 
	return 0;
}
  • 用牛顿迭代法求输入的数的平方根。
    欲求a的平方根,首先猜测一个值x1=a/2(也可以是随便什么其他值)作为其平方根,然后根据下面的迭代公式算出x2,再将x2代入公式右边算出x3…直到连续两次算出的xn和xn+1的差的绝对值小于某个值ε,即认为找到了足够精确的平方根。这个ε值取得越小,计算出来的平方根就越精确。
    迭代公式: x n + 1 = ( x n + a / x n ) / 2 x_{n+1} = (x_n+a/x_n)/2 xn+1=(xn+a/xn)/2
 
#include <iostream>
using namespace std;
double EPS = 0.001; //用以控制计算精度
int main()
{
	double a;
	cin >> a ; //输入a,要求a的平方根 
	if( a >= 0) {
		double x = a/2, lastX = x + 1 + EPS;//确保能够进行至少一次迭代  x为当前的根 lastX为上一次计算的根
		while( x - lastX > EPS || lastX - x > EPS){ //只要精度未达要求, 两个根差的绝对值大于EPS
			lastX = x;
        	x = (x + a/x)/2;	
		}
		cout << x; 
    }
	else
		cout << "It can't be nagitive.";
return 0;
}
do…while循环

如果希望循环至少要执行一次,就可以使用do…while语句。

do{
	语句组;
}while(表达式);

每执行一次循环后,都要判断“表达式”的值是否为真,如果真就继续循环,如果为假,就停止循环。

  • 输出1到10000以内所有2的整数次幂:
int n = 1;
do{
	cout<<n<<endl;
	n *= 2;
}while(n<10000);
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值