双11也不能阻挡我学习的心!

[TOC]

问题引入

题目内容:

定义一个含10个整型元素的一维数组,从键盘上输入10个元素值,求去掉最大值和最小值之后的元素平均值.

输入格式:

用循环控制依次输入10个元素值,scanf语句中的格式控制串为: “%d”

输出格式:

输出平均值, printf中的格式控制串为 “%lf\n”

输入样例:

1
2 3 4 5 6 2 4 6 4 3

输出样例:

1
3.833333

理解1

一般人看到这种题目,下意识会认为是去掉一个最大值一个最小值,再计算数组其他元素的最大值

毕竟很多体育赛事都是这么计算选手的得分的

实际上这道题并不是这么要求的,这点我们后面再提

先来看看如何去掉数组中的一个最大值、一个最小值吧!

去除一个最大/最小值

先理清思路

  • 需要找到数组中的最大值和最小值
  • 在计算平均值的时候需要剔除这两个值

想清楚这两点后,方法就很明确了

之前我写过一篇博客,有关如何查找数组中最大值的 [链接]

这里我们就能用上那个博客里面的方法,不过是以自定义函数的方式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int sp1(int arr[], int sz, int* pm)
{
int i = 0;
for (i = 0; i < sz; i++)
{
if (arr[i] > *pm)//找出最大值
{
*pm = arr[i];
}
}
for (int k = 0; k < sz; k++)
{
if (arr[k] == *pm)//确认最大值的数值
{
return k;//返回该最大值的下标
}
}
}

找出最小值的代码同上,只需要将其中的>更改为<

在main函数中,我们需要设立两个变量来接收得到的最大值和最小值的下标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
int arr[10] = { 0 };
int a, b = 0;
double ave,sum= 0;
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}

int sz = sizeof(arr) / sizeof(arr[0]);
a =sp1(arr, sz, &max);
b =sp2(arr, sz, &min);

for (int k = 0; k < 10; k++)
{
if (k != a && k != b)
{
sum = sum + arr[k];
}
}
ave = sum / 8;
printf("%lf\n", sum);
printf("%lf\n", ave);
return 0;
}

在最后计算sum的时候,只需要用if语句让K不等于最大值和最小值的下标,就能剔除这两个值

同时,我们的平均数也只需要除以8即可

运行结果

键入数组中元素1-10,程序成功的输出了剔除1和10之后8个元素的平均值

image-20211111195107174

但当我们把题目示例输进去时,得出的答案却和题目要求不同

image-20211111201040941


题目实际要求

上面提到,这道题的要求并不是只剔除一个最大值和最小值

而是剔除所有的最大值和最小值

1
2 3 4 5 6 2 4 6 4 3

观察输入样例可以发现,这10个数字的最大值是6,最小值是2

但是不管是最小值2和最大值6,都不止一个

题目要求的就是要将这里面的所有2和6剔除掉,再计算剩余数据的平均值

解题思路1&2

对上面的代码进行优化,以循环的方式继续寻找最大值的下标

缺点:此方法可能会出现多删的情况

更改代码,在找到最大值下标后,查找数组中有几个元素同这个最大值相同,再返回他们的下标

此方法需要用数组来存放找到的元素的下标,较为麻烦


解题思路3 -冒泡排序

先对数组进行冒泡排序,再剔除两边的最大值和最小值

这里我选择的就是解题思路3


冒泡排序的方式可以参考我之前的博客 [链接]

这里只贴出主函数内需要编写的内容

计数器

因为需要剔除多个最大(小)值

所以这里我们需要用一个变量进行计数

每当我们找到和已知最大值相同的数字的时候,count都会++(初值为1)

当循环走到第一个小于最大值的数后,循环就会终止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int count2 = 1;
for (int k = 8; k >0 ; k--)
{
if (arr[k] == arr[9])
{
arr[k] = 0;//令最大值为0
count2 ++;
}
else
{
break;
}
}

查找最小值的代码同上,但是for循环中的条件需要更改

注意,这里的下标k必须从8开始而不是从9

因为经过冒泡排序后,arr[9]本身就是数组中的最大值

若从它开始循环判断,就会直接把最大值赋值为0

程序就出bug了


主函数代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int main()
{
int arr[10] = { 0 };
int a, b = 0;
double ave, sum = 0;
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
int sz = sizeof(arr) / sizeof(arr[0]);
//先对数组进行冒泡排序
bubble_sort(arr, sz);

//此时下标0和9即为最大最小值
int max = arr[0];
int min = arr[9];

int count1 = 1;
int count2 = 1;
for (int j = 1; j < 10; j++)
{
if (arr[j] == arr[0])
{
arr[j] = 0;//令最小值为0
count1 ++;
}
else
{
break;
}
}
for (int k = 8; k >0 ; k--)
{
if (arr[k] == arr[9])
{
arr[k] = 0;//令最大值为0
count2 ++;
}
else
{
break;
}
}
//令前后两个最大最小值为0
arr[0] = 0;
arr[9] = 0;

for (int k = 0; k < 10; k++)
{
sum = sum + arr[k];
}
//除去已知的所有最大最小值,计算平均数
ave = sum / (10- count1- count2);

//printf("%lf\n", sum);
printf("%lf\n", ave);
return 0;
}

在最后计算平均数的时候,我们需要剔除count1和count2(10减去后即为剩余元素的个数)

这时候得出的答案就和题目所给示例相同了

image-20211111201220285

你学废了嘛?

反正我是废了