【context】
题目描述
国中生Chino总是做不完数学作业,Cocoa想来帮忙,但作业太多了,怎么也做不完。
Chino的数学作业由T(1≤T≤100)张试卷组成,每张试卷上有n(1≤n≤103)个数a1..n(1≤a≤5000),Chino需要算出这些数的极差和方差。
极差是一个整数,方差是一个浮点数,要求保留到小数点后3位。
虽然题目很简单,但计算量对于Chino来说实在太大啦!你能帮一帮她吗?
P.S.:一个数列的极差是指数列中最大的数减去最小的数,方差是指算出数列中每个数与数列平均值之差的平方后,对其求和,再除以数列元素个数得到的结果。
输入描述
输入的第一行有一个数T,表示试卷的数量;接下来的每两行——第一行有一个数n,表示当前试卷上数字的格式;第二行有n个数字,表明这张试卷上的每一个数。
输出描述
对每张试卷,输出一行两个数,分别表示这些数字的极差和方差,中间用空格分开。其中极差是整数,方差是保留到小数点后3位的浮点数。
示例1
输入
2
5
5 4 3 2 1
7
333 494 655 991 101 591 941
输出
4 2.000
890 86075.959
初次尝试(×
#include<iostream>
using namespace std;
int main()
{
int MAX(int a[5000]);
int MIN(int a[5000]);
float VARP(int a[5000]);
int x, n, m, a[5000], i, j, max, min;
float k;
cin >> x;
for (i = 0; i < x; i++)
{
cin >> n;
for (j = 0; j < n; j++)
{
cin >> a[j];
}
}
for(i=0;i<x;i++)
{
max = MAX(a);
min = MIN(a);
m = max - min;
cout << m << " ";
k = VARP(a);
cout << k ; //题目要求以三位小数的形式输出 ×
}
}
int MAX(int a[5000])
{
int i,max;
for (i = 0; a[i] != '\0'; i++) //这是整型数组而不是字符型数组,不是以'\0'结束 ×
{
if (a[0] < a[i])
a[0] = a[i]; //原数组发生改变 ×
}
max = a[0];
return max;
}
int MIN(int a[5000])
{
int j,min;
for (j = 0; a[j] != '\0'; j++) // ×
{
if (a[0] > a[j])
a[0] = a[j]; // ×
}
min = a[0];
return min;
}
float VARP(int a[5000])
{
int i, sum = 0;
float h = 0.000, v;
float aver;
for (i = 0; a[i] != '\0'; i++) // ×
{
sum += a[i];
}
aver = sum / i;
for (i = 0; a[i] != '\0'; i++) // ×
{
h += (a[i] - aver) * (a[i] - aver);
}
v = h / i;
return v;
}
结果如图(尝试代入 1张试卷 6个数)
明显是错误的(错误点在程序中已注释)
- for (i = 0; a[i] != '\0'; i++) //这是整型数组而不是字符型数组,不是以'\0'结束 ×
( 又是一个大错特错)循环的判断条件需要找出数组的长度,不妨将主函数中的数组长度n作为实参传递给所需函数中的形参,直接进行判断;
- if (a[0] < a[i])
a[0] = a[i]; //原数组发生改变 ×
(在写程序时很容易忽略这一点)解决办法就是:定义一个变量来接收所需的最大值和最小值;
- cout << k ; //题目要求以三位小数的形式输出 ×
在这里就使用printf进行输出即可。
改进(发现仍有错误
#include<iostream>
using namespace std;
int main()
{
int MAX(int a[5000], int len); //将main函数中的数组长度传给定义的函数
int MIN(int a[5000], int len); //此处是函数声明
float VARP(int a[5000], int len);
int x, n, m, a[5000], i, j, max, min;
float k;
cin >> x;
for (i = 0; i < x; i++)
{
cin >> n;
for (j = 0; j < n; j++)
{
cin >> a[j];
}
}
for (i = 0; i < x; i++)
{
max = MAX(a, n); //函数的调用
min = MIN(a, n);
m = max - min;
cout << m << " ";
k = VARP(a, n);
printf("%.3f\n", k); //以%m.nf的形式输出,n代表小数的位数
}
}
int MAX(int a[5000], int len)
{
int i, max = a[0]; //把a[0]的值赋给max,再进行判断就不会改变原数组
for (i = 0; i < len; i++)
{
if (max < a[i])
max = a[i];
}
return max;
}
int MIN(int a[5000], int len)
{
int j, min = a[0];
for (j = 0; j < len; j++) //此处for循环就可以正常进行
{
if (min > a[j])
min = a[j];
}
return min;
}
float VARP(int a[5000], int len)
{
int i, sum = 0;
float h = 0.000, v;
float aver;
for (i = 0; i < len; i++)
{
sum += a[i];
}
aver = sum / i;
for (i = 0; i < len; i++)
{
h += (a[i] - aver) * (a[i] - aver);
}
v = h / i;
return v;
}
结果如图(尝试带入简单数据)
发现两组数据相同,出现数据被覆盖的情况。
问题出在这一部分,main函数传给定义的MAX和MIN函数 的数组a的值始终是最后一组。那么此时有两种解决方案:
①将原数组改成二维数组,再进行for循环的输出,则不会覆盖;
②将max和min放入第一个for循环中,把m变成一个接收方差的一维数组。
显然对于已有程序,第二种较为简便。
【另】double类型精度比float高,在尝试过后发现由于精度问题导致结果错误,在以下程序中进行了一些改变;在计算极差的函数中,同样由于精度问题导致的结果也进行了一些优化。
正确程序
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int MAX(int a[5000], int len);
int MIN(int a[5000], int len);
double VARP(int a[5000], int len);
int x, n, m[500], a[5000], i, j, max, min;
double k[500]; //提高精度
cin >> x;
for (i = 0; i < x; i++)
{
cin >> n;
for (j = 0; j < n; j++)
{
cin >> a[j];
}
max = MAX(a, n);
min = MIN(a, n);
m[i] = max - min; //定义一个数组接收方差
k[i] = VARP(a, n); //定义一个数组接收极差
}
for (i = 0; i < x; i++)
{
cout << m[i] << " ";
printf("%.3lf\n", k[i]);
}
}
int MAX(int a[5000], int len)
{
int i, max = a[0];
for (i = 0; i < len; i++)
{
if (max < a[i])
max = a[i];
}
return max;
}
int MIN(int a[5000], int len)
{
int j, min = a[0];
for (j = 0; j < len; j++)
{
if (min > a[j])
min = a[j];
}
return min;
}
double VARP(int a[5000], int len)
{
int i, sum = 0;
double h = 0.0, v;
double aver;
for (i = 0; i < len; i++)
{
sum += a[i];
}
aver = sum / (i * 1.0); //提高精度
for (i = 0; i < len; i++)
{
h += pow(a[i] - aver,2);
}
v = h / i;
return v;
}
程序优化(待更新
对数组的掌握以及函数传参还需要再巩固。