线性序列中同时求出最大值和最小值

在一个线性序列中同时求出最大值和最小值

题目描述:在一个线性序列中同时求出最大值和最小值;

   方法一:初时看到这个题目,第一想法就是设定一个初始的最大值和最小值,然后循环遍历数组,进行比较,如下所示:

   

#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中的最大元和最小元;

扫描二维码关注公众号,回复: 2688720 查看本文章

    按照分治法的步骤:

    划分:把n个数分为两半,即:划分点为d=(l+r)/2,两个区间为:[l,d]和[d+1,r];

    递归求解:求左半部分的最小值min1和最大值max1,以及右半部分的最小值min2和最大值max2;

    合并:所有数的最大值为max,最小值为min;

    运行如下:

    

#include <stdio.h>
#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)来作为参数,而没有减一!  

 在上面的实现中,我们需要总结一些问题:

    一.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)

    鉴于楼主水平有限,欢迎大家拍砖~

猜你喜欢

转载自blog.csdn.net/qq_29027865/article/details/53006873
今日推荐