Bootstrap

【杂记】之语法学习第二课循环与数组

while 循环

回顾上节的最后我们学了用 if 进行判断,

if(条件)
{
    操作;
}

while 循环也是一个类似的结构:

while(条件)
{
	操作;
}

区别在于 while 没有类似 else 的操作,而且如果满足条件,则会重复执行大括号内的操作;而if只会执行其中的一次操作。

在这里插入图片描述

题目描述

给定一个小于等于 1000 1000 1000 的正整数 n n n ,求 1 1 1 n n n 中所有数的累加和。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n ;
	scanf("%d" ,&n);
	int i = 1 , sum = 0 ;
	while(i <= n)
	{
		sum += i ;
		i ++ ;
	}
	printf("%d" ,sum) ;
	return 0 ;
}

数学方法可以直接考虑利用等差数列求和公式 ( 首项 + 末项 ) × 项数 2 {(首项 + 末项) \times 项数}\over 2 2(首项+末项)×项数 ,但是这个题数据范围比较小,所以也可以通过模拟的方式来完成这个过程。

注意一定要给 sum 赋初始值0

当我们在主函数内声明变量时,通常没有固定的初始值,我们将 i i i 1 1 1 加到 n n n ,每次加一,实现了从 1 1 1 n n n 所有整数的枚举,然后将这些数全部加到 s u m sum sum 上,则 s u m sum sum 即为所求的答案。

题目描述

给出 n n n n n n 个整数 a i a_i ai,求这 n n n 个整数中最小值是什么。

输入格式

第一行输入一个正整数 n n n,表示数字个数。

第二行输入 n n n 个非负整数,表示 a 1 , a 2 … a n a_1,a_2 \dots a_n a1,a2an,以空格隔开。

输出格式

输出一个非负整数,表示这 n n n 个非负整数中的最小值。

样例输入
8
1 9 2 6 0 8 1 7
样例输出
0
提示

数据保证, n ≤ 100 n\le100 n100 0 ≤ a i ≤ 1000 0\le a_i \le 1000 0ai1000

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n , a , ans = 1000000000;
	scanf("%d" ,&n);
	while(n)
	{
		scanf("%d" ,&a) ;
		if(ans > a) ans = a ;
		n -- ;
	}
	printf("%d" ,ans) ;
	return 0 ;
}

此时的 n n n 起到计数的作用,当然也可以另外设置一个 i i i 写成

int i = 1 ;
while(i <= n)
{
	scanf("%d" ,&a) ;
	if(ans > a) ans = a ;
	i ++ ;
}

或者利用 n ++ 这一写法先调用后修改的性质,写成

	while(n --)
	{
		scanf("%d" ,&a) ;
		if(ans > a) ans = a ;
	}

for循环

f o r for for 循环结构看起来可能更麻烦,但是也挺好理解的:

for(初始; 判断 ; 更新)
{
  操作;
  //循环体
}

当进入 f o r for for 循环时先初始化,然后判断条件是否成立,若不成立则退出循环,若成立则执行相应操作,执行完操作后更新,再次判断条件是否成立,若不成立则退出,若成立则再次进行相应操作。在这里插入图片描述
我们用 f o r for for 循环再写一遍上面两道题

题目描述

给定一个小于等于 1000 1000 1000 的正整数 n n n ,求 1 1 1 n n n 中所有数的累加和。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n , sum = 0 ;
	scanf("%d" ,&n);
    for(int i = 1; i <= n ; i ++)
    {
    	sum += i ;
	}
	printf("%d" ,sum) ;
	return 0 ;
}

其中 f o r for for 循环后的大括号也是可加可不加,如果只进行单个操作不用加,多个操作括起来。

题目描述

给出 n n n n n n 个整数 a i a_i ai,求这 n n n 个整数中最小值是什么。

输入格式

第一行输入一个正整数 n n n,表示数字个数。

第二行输入 n n n 个非负整数,表示 a 1 , a 2 … a n a_1,a_2 \dots a_n a1,a2an,以空格隔开。

输出格式

输出一个非负整数,表示这 n n n 个非负整数中的最小值。

样例输入
8
1 9 2 6 0 8 1 7
样例输出
0
提示

数据保证, n ≤ 100 n\le100 n100 0 ≤ a i ≤ 1000 0\le a_i \le 1000 0ai1000

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n , a , ans = 1000000000;
	scanf("%d" ,&n);
	for(int i = 1 ; i <= n ; i ++)
	{
		scanf("%d" ,&a) ;
		if(a < ans) ans = a ; 
	}
	printf("%d" ,ans) ;
	return 0 ;
}

此时的 i i i 没有参与任何运算,只是用来计数也是可以的。

局部变量

注意,在两个 f o r for for 循环的举例代码中,我们的 i i i 是在 f o r for for 循环的初始化部分声明的变量,因此只能作为局部变量在大括号内使用,而不能在循环结构之外随意调用!

break; 与 continue;

break; 操作用在循环体中,表示退出循环。

continue;操作用在循环体中,表示跳过本次循环的剩余操作,进入下一次循环。

当多层循环嵌套使用时,以上两项操作若在内层循环中,只会对内层循环产生影响。

继续做题巩固一下

题目描述

已知: S n = 1 + 1 2 + 1 3 + … + 1 n S_n= 1+\dfrac{1}{2}+\dfrac{1}{3}+…+\dfrac{1}{n} Sn=1+21+31++n1。显然对于任意一个整数 k k k,当 n n n 足够大的时候, S n > k S_n>k Sn>k

现给出一个整数 k k k,要求计算出一个最小的 n n n,使得 S n > k S_n>k Sn>k

输入格式

一个正整数 k k k

输出格式

一个正整数 n n n

样例输入
1
样例输出
2

提示

【数据范围】

对于 100 % 100\% 100% 的数据, 1 ≤ k ≤ 15 1\le k \le 15 1k15

#include <bits/stdc++.h>
using namespace std;
int main()
{
	double ans = 0 , k ;
	int n = 1 ;
	scanf("%lf" ,&k) ;
	for( ; ans <= k ; n ++)
		ans += 1.0 / n ;
	printf("%d" ,n - 1) ;
	return 0;
}

这个写法中 n n n 在最后输出,因此设为全局变量,同时 f o r for for 循环中无论是 初始化判断 还是 更新 其实都是可以省略掉的,但是该有的结构还是要有,比如两个分号。

双层循环

题目描述

给出 n n n,请输出一个直角边长度是 n n n 的数字直角三角形。所有数字都是 2 2 2 位组成的,如果没有 2 2 2 位则加上前导 0 0 0

输入格式

输入一个正整数 n n n

输出格式

输出如题目要求的数字直角三角形。

样例输入
5
样例输出
0102030405
06070809
101112
1314
15
提示

数据保证, 1 ≤ n ≤ 13 1\le n\le13 1n13

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n , tot = 1;
	scanf("%d" ,&n) ;
	for(int i = 1 ; i <= n ; i ++)//第i层
	{
		for(int j = i ; j <= n ; j ++)//第i层有n - i + 1 个数,因此 j 从 i 到 n
		{
			printf("%02d" ,tot) ;
			tot ++ ;
		}
		printf("\n") ;
	}
	return 0;
}

这个就体现了双重循环,每次进入内层的 j循环 时都重新把 j j j 初始化成了当前的 i i i ,用 t o t tot tot 记录这个数字三角形到了数字几。

printf("%02d" ,tot) ; 的写法就是说不满两位的数字通过补前导 0 0 0 的方式补成两位。

然后每次输出完当前的那一层就换行。

数组

当我们需要 3 3 3 个变量时可以声明 a , b , c a , b , c a,b,c ,那么当我们需要 100 100 100 个时呢?

可以 int a[100]; 意思是声明整型数组 a a a 中括号里数字类比数列的下标,调用时就 a [ 1 ] , a [ 2 ] , a [ 3 ] a[1],a[2],a[3] a[1],a[2],a[3] 这样的用。

int a[100] ; //声明一个包含100个元素的数组
a[1] = 666 ; //赋值与正常变量一样
int k = 5 ;
a[k] = 123 ;//下标可以是一个数,也可以是变量
a['a'] = 456 ; //甚至可以是一个字符,相当于其对应ascii码值
a[k + 1] = a[k] + a[1] ;
printf("%d" ,a[k + 1]) ; //输出

特别的,我们用什么样的 关键字 声明这个数组,这个数组就是什么数据类型的,就是说也可以用 char 声明字符型数组 或者 用 double 声明浮点型数组;基于下标可以是变量这一特性,也很容易地可以和 循环 结合起来使用;注意: 数组的下标是从 0 0 0 开始,到 n − 1 n - 1 n1 结束,即声明一个 int a[100] 这样的数组,只有下标为从 0 0 0 99 99 99 之间的整数时才是合法的!

题目描述

陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 10 10 10 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 30 30 30 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。

现在已知 10 10 10 个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。

输入格式

输入包括两行数据。第一行包含 10 10 10 100 100 100 200 200 200 之间(包括 100 100 100 200 200 200)的整数(以厘米为单位)分别表示 10 10 10 个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。第二行只包括一个 100 100 100 120 120 120 之间(包含 100 100 100 120 120 120)的整数(以厘米为单位),表示陶陶把手伸直的时候能够达到的最大高度。

输出格式

输出包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。

样例输入
100 200 150 140 129 134 167 198 200 111
110
样例输出
5
#include <bits/stdc++.h>
using namespace std;
int apple[20];
int main()
{
	for(int i = 1 ; i <= 10 ; i ++)
		scanf("%d" ,&apple[i]) ;
	int tall , high , ans = 0 ;
	scanf("%d" ,&tall) ;
	high = tall + 30;
	for(int i = 1 ; i <= 10 ; i ++)
		if(high >= apple[i]) ans ++;
	printf("%d" ,ans) ;
	return 0;
}

学了 循环数组 之后就不需要声明 10 10 10 个变量挨个输入了,在 主函数 内声明的变量在不赋初始值的情况下可能是任意数,在 主函数 外声明变量时默认为 0 0 0

二维数组

思考我们 一维数组 只是多一个下标,其实还可以有 二维数组 ,即int a[110][110]; 这样的,可以思考为 一维数组 是一个 数列二维数组 是一个矩阵,有横坐标和纵坐标,可以类比线代里的矩阵。

想要访问每个位置可以类比一维数组时用循环里的变量当做下标,二维数组就可以用双重循环来访问每个下标。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;