【题目描述】
题目1(必要的存储量):数组可以用来保存很多数据,但在一些情况下,并不需要把数据保存下来。下面哪些题目可以不借助数组,哪些必须借助数组?请编程实现。假设输入只能读一遍。
□输入一些数,统计个数。
□输入一些数,求最大值、最小值和平均数。
□输入一些数,哪两个数最接近。
□输入一些数,求第二大的值。
□输入一些数,求它们的方差。
□输入一些数,统计不超过平均数的个数。
【题目来源】
刘汝佳《算法竞赛入门经典 第2版》第3章 思考题1 必要的存储量
【解析】
使用数组的好处是可以随时使用所有输入值,不用数组每次只能使用当前输入值。
因此,无需使用数组的条件:当每次要更新输出值时,只需使用当前输入值。即更新值只与原值和最近一次输入的数有关,与其他数无关。
为简化起见,假设所有输入的数都是整数,输入个数不超过100个。
1.输入一些数,统计个数
这很简单,只要定义一个计数器cnt,每输入一个数计数1次就可以了。
输入数的个数只与原个数和最近一次输入的数有关,因此可以不用数组。
#include<stdio.h>
int main(){
int n, cnt=0;
while(scanf("%d", &n)==1) cnt++;
printf("%d\n", cnt);
return 0;
}
2.输入一些数,求最大值、最小值和平均数。
可以在每次循环时更新4个变量的值:最大值、最小值、数的和、数的个数,这些值都只与原值和最近一次输入的数有关,所以可不用数组。
#include<stdio.h>
//定义整型最大值INT_MAX、最小值INT_MIN的头文件
#include<limits.h>
int main(){
int n, cnt=0, sum=0, max=INT_MIN, min=INT_MAX;
while(scanf("%d", &n)==1){
sum += n;
cnt++;
if(max<n) max=n;
if(min>n) min=n;
}
printf("%d %d %f\n", max, min, sum*1.0/cnt);
return 0;
}
3.输入一些数,哪两个数最接近。
每输入一个新数,都要算出这个数与已输入数的最小差new_min,然后和输入前的最小差min比较大小。显然,new_min的值与之前输入的数有关,所以此时需要数组。
可以按上述思路,每输入一个新数都与之前所有数比较,代码如下:
#include<stdio.h>
int a[100];
int main(){
int m, n, i=0, min, new_min;
scanf("%d", &a[i++]);
scanf("%d", &a[i++]);
min=abs(a[0]-a[1]);
m=0;
n=1;
while(scanf("%d", &a[i])==1){
for(int j=0; j<i; j++){
new_min=abs(a[j]-a[i]);
if(new_min<min){
min=new_min;
m=j;
n=i;
}
}
i++;
}
printf("%d %d\n", a[m], a[n]);
return 0;
}
因为数据已存入数据,故也可以在所有输入数据输入完成后通过双层循环找出最接近的两个数。代码如下:
#include<stdio.h>
int a[100];
int main(){
int m, n, i=0, min, new_min;
while(scanf("%d", &a[i++])==1);
min=abs(a[0]-a[1]);
m=0;
n=1;
for(int j=2; j<i; j++)
for(int k=0; k<j; k++){
new_min=abs(a[j]-a[k]);
if(new_min<min){
min=new_min;
m=k;
n=j;
}
}
printf("%d %d\n", a[m], a[n]);
return 0;
}
输入数据可能存在多组最接近的数,比如:-2 -3 3 3 4 5 1 7 6 6中的(3,3)、(6、6),简化起见,只输出第一组。
4.输入一些数,求第二大的值。
我们可以设置两个变量:最大值max,第二大值smax。每输入一个数,只需要将其与max、smax比较即可算出新的max、smax,与以前输入的数无关,所以可以不用数组。
#include<stdio.h>
int main(){
int n, max, smax, flag=0;
scanf("%d", &max);
scanf("%d", &n);
if(n<max) {flag=1; smax=n;}
else if(n>max) {flag=1; smax=max; max=n;}
while(scanf("%d", &n)==1){
if(n>max) {flag=1; smax=max; max=n;}
else if(n<max && (n>smax || flag==0)){
flag=1;
smax=n;
}
}
if(flag) printf("%d\n", smax);
else printf("no");
return 0;
}
5.输入一些数,求它们的方差。
方差的基本计算公式为:方差 = ∑(数据值 - 平均值)² / 总个数。
每输入一个数后,只能计算出当前输入所有数的平均值,而公式中的平均值是输入完成后所有数的平均值,所以“数据值-平均值”的值与以后输入的数有关,无法在每输入一个数更新此值,因此需要数组。代码如下:
#include<stdio.h>
int a[100];
int main(){
int i=0, sum=0;
double fsum=0;
while(scanf("%d", &a[i])==1){
sum += a[i];
i++;
}
double avr=(double)sum/i;
for(int j=0; j<i; j++) {
fsum += (a[j]-avr)*(a[j]-avr);
}
printf("%f\n", fsum/i);
return 0;
}
6.输入一些数,统计不超过平均数的个数。
和题目5的道理一样,平均值在输入所有数据后才能求出,因此无法在每输入一个数时让其与平均值比较,需要使用数组。代码如下:
#include<stdio.h>
int a[100];
int main(){
int i=0, sum=0, cnt=0;
while(scanf("%d", &a[i])==1){
sum += a[i];
i++;
}
double avr=(double)sum/i;
for(int j=0; j<i; j++) {
if(a[j]-avr <= 0) cnt++;
}
printf("%d\n", cnt);
return 0;
}