在一个线性序列中同时求出最大值和最小值
题目描述:在一个线性序列中同时求出最大值和最小值;
方法一:初时看到这个题目,第一想法就是设定一个初始的最大值和最小值,然后循环遍历数组,进行比较,如下所示:
#include <stdio.h>
#include <stddef.h>
void find1(int a[],int n,int *min,int *max)
{
int i;
*min=a[0];
*max=a[0];
for(i=1;i<n;i++){
if(a[i]>*max) *max=a[i];
else if(a[i]<*min)
*min=a[i];
}
}
int main()
{
int a[]={1,9,6,4,5,22,13,56,45};
int min,max;
find1(a,sizeof(a)/sizeof(int),&min,&max);
printf("%d\t%d\n",min,max);
return 0;
}
但是这种方法的比较次数就比较多了,一个循环内进行两次,共需要比较2(n-1)次;
方法二:接着再往下想,升级版:同时保存当前所得到的最大值和最小值,之后依次从序列中取出两个数并进行比较,其中较小的一个与当前的最小值进行比较,较大的一个与当前的最大值进行比较,然后更新当前的最大值和最小值,按照这一个过程,每两个元素需要进行3次比较,于是最后的比较次数为3*(n/2)次;
但是在这种升级版方法的实现中,需要注意的是:为了保证之后的元素有偶数个,设定最大值和最小值的初值时需要结合n的奇偶性,若n为奇数,则最大值和最小值的初值都取第一个元素,若n为偶数,则首先比较序列的前两个元素,较小的一个作为最小值的初值,较大的一个作为最大值的初值,实现过程如下:
#include <stdio.h>
#include <stddef.h>
void find2(int a[],int n,int *min,int *max)
{
int i;
//首先判断其个数是奇数还是偶数
if(n%2==1)
{ //若是奇数,则对于最大值和最小值均为第一个元素,后面的两两比较
*min=a[0];
*max=a[0];
i=1;
}
else
{ //若是偶数,则比较其前两个值,大的做最大值,小的做最小值
if(a[0]>a[1])
{
*max=a[0];
*min=a[1];
}
else
{
*max=a[1];
*min=a[0];
}
i=2;
}
for(;i<n;i+=2)
{
if(a[i]>a[i+1])
{
if(a[i]>(*max))
*max=a[i];
if(a[i+1]<(*min))
*min=a[i+1];
}
else
{
if(a[i+1]>(*max))
*max=a[i+1];
if(a[i]<(*min))
*min=a[i];
}
}
}
int main()
{
int a[]={1,9,6,4,5,22,13,56,45};
int min,max;
find2(a,sizeof(a)/sizeof(int),&min,&max);
printf("%d\t%d\n",min,max);
return 0;
}
方法三:分治法计算,把集合a分为a1和a2两个子集,每个子集都有n/2个元素,应用递归方法找出两个子集的最大元和最小元,比较得到的两个最大元和最小元,即可得到整个集合a中的最大元和最小元;
按照分治法的步骤:
划分:把n个数分为两半,即:划分点为d=(l+r)/2,两个区间为:[l,d]和[d+1,r];
递归求解:求左半部分的最小值min1和最大值max1,以及右半部分的最小值min2和最大值max2;
合并:所有数的最大值为max,最小值为min;
运行如下:
#include <stdio.h>注:楼主开始出现了错误,原因是在主函数中调用时,直接使用了sizeof(a)/sizeof(int)来作为参数,而没有减一!
#include <stddef.h>
void find3(int a[],int left,int right,int &min,int &max)
{
int max1,min1,max2,min2;
int d;
if(left==right) max=min=a[left];
else if(right==left+1)
{
if(a[right]>a[left])
{
max=a[right];min=a[left];
}
else{
max=a[left];min=a[right];
}
}
else{
d=(left+right)/2;
find3(a,left,d,min1,max1);
find3(a,d+1,right,min2,max2);
if(max1>max2) max=max1;
else max=max2;
if(min1<min2) min=min1;
else min=min2;
}
}
int main()
{
int a[]={1,9,6,4,5,22,13,56,45};
int min,max;
//find2(a,sizeof(a)/sizeof(int),&min,&max);
find3(a,0,sizeof(a)/sizeof(int)-1,min,max);
printf("%d\t%d\n",min,max);
return 0;
}
在上面的实现中,我们需要总结一些问题:
一.sizeof(a)/sizeof(int)可以求算出数组的长度n,借此进行简单计算,但是在表示数组下标时,需要减一;
二.在进行参数传递时,需要对参数的值进行改变时,需要运用引用传递,而引用传递有两种方法,一个是使用指针传递,一个是传递地址,如下所示:
指针传递:主函数中:find2(a,sizeof(a)/sizeof(int),&min,&max)
函数中:void find2(int a[],int n,int *min,int *max)
传递地址:主函数中:find3(a,0,sizeof(a)/sizeof(int),min,max);
函数中:void find3(int a[],int left,int right,int &min,int &max)
鉴于楼主水平有限,欢迎大家拍砖~