C++锦标赛法计算最大值与次大值

本文介绍了锦标赛法在C++中计算数组最大值和次大值的原理与实现。通过两两比较,逐步淘汰较小的数,最终找到最大值。同时,通过对比较过程的分析,解决了如何找到次大值的问题,即使在有多个最大值的情况下。文章提供了解决方案,适用于任意数量的元素,不仅限于2的n次方个数,并给出了具体的程序逻辑。
摘要由CSDN通过智能技术生成

锦标赛法计算最大值与次大值

1.该程序用于计算n个数组元素的最大值与次大值,使用的是锦标赛算法,那么有人会问了,为什么不用冒泡排序法呢,本人认为冒泡排序的时间复杂度太高,所以使用了一种两两PK的算法来减少时间复杂度。

2.刚开始的时候,发现这种竞标赛算法只适合含有2的n次方个数的元素进行计算,所以我把该算法优化了一下,使其能够用于任意数量的元素比较。

3.该算法逻辑性较强,请读者尝试画图理解.
①首先我们随便输入8个数:5,8,4,2,1,3,9,6。
②将他们两两比较,把大的放前面,就变成了8,5,4,2,3,1,9,6。
③这时,将两个两个比较过的元素看为一段,即:(8,5)(4,2)(3,1)(9,6)
④将每段的第一个元素两两比较,大的放前面:8,5,4,2,9,6,3,1。
⑤同理,将比较过的四个元素放一起(8,5,4,2)(9,6,3,1)
⑥再两两比较变为:9,6,3,8,2,5,4,2。

看到这可能就有人疑惑了,前面不都是比较之后,两段两段交换吗,第六步的结果不应该是9,6,3,1,8,5,4,2吗? 其实这样说对也不对,其中涉及到一种数学逻辑问题。这种方法计算最大值很简单,但是我们也需要找到次大值,那么次大值怎么找呢。
你不妨试试,你随机找8个数,按照刚刚的方法画图比较,就会发现,不管这8个数有多大或者多小,次大值一定一定跟最大值比较过一次。所以我把每个比较过的数都放一起,找到了最大值,那么他后面的那些跟他比较过的数字中的最大值不就是次大值了吗!所以我定义一个变量i=1,用来表示跟这个数比较的次数,也就是这个数有多少个"小跟班",每循环比较一次,只交换这个数和它的小跟班,并将刚刚和他比较的数放到小跟班中,其他的数不动,然后i+1。上述第六步中,每个最大数都比较了三次,所以每段最大值有三个"小跟班",最后的结果就长那样。

思路

将n个数字放在数组中,将相邻的两个数字两两分组并进行比较,较大的数胜出,进入到下一轮继续和另一个数比较,以此类推,直到只剩下最后一位数就是最大值,这就是锦标赛法。
在这里插入图片描述通过上面的图片可以清晰的了解到锦标赛法的步骤,但是该方法有三大问题:
①最大值很容易找到,但是次大值呢?
②此方法只适用于含有2^n个数字找最大值与次大值,刚好能在每次比较时都能两两分组比较
③如果n个数字中不只一个数是最大值,那么怎么找到第二大的次大值呢?

解决三大问题

最大值很容易找到,但是次大值呢?

根据上面的图,你会发现一个有趣的现象,无论这8个数的顺序是怎样,无论这8个数多大或多小,次大值一定与最大值比较过一次,读者要是不信可以画图试一试(ˉ▽ˉ;),那么我们就可以每次比较后,将最大的那个数放前面,将较小的数变成最大数的‘小跟班’,待到所有数比较完后,数组中的第一个数就是最大值,而这个数的一群小跟班中的最大值就是整个数组的次大值。
在这里插入图片描述
由上图一开始每一段长为1,比较一次后每一次长为2,第三次每段长为4,不妨取一整型变量p,记录每一次比较后每一段数组的长度。由第一行到第二行两两比较,大的放前面,第二行到第三行两两段的第一个数字比较,大的那一段放前面,然后比较过的较小值放到小跟班后面,第三行到第四行,每段长度为4,即(5 2 4 1)与(8 3 7 6)两段数字比较,8比5大,所以8那一段数字移到前面,就变为(8 3 7 6 5 2 4 1),然后刚刚与数字8比较的数字5变成数字8的小跟班,即(8 3 7 5 6 2 4 1),所以得出最大值为第一个数字8,次大值为该数字小跟班中(3 7 5)的最大值7。

void MAX1(int a[],int n,int k)
{
   
	int i,j,q,p=1,t,temp;//i:小跟班个数,p:每段元素的个数,q:循环时两两比较时方便用以及下一次的p 
	for(i=1;i<=k;i++)
	{
   
		q=2*p;
		for(t=0;t<n;t=t+q)//循环,两两比较 
		{
   
			two(a,p,t,i);
		}
		p=q;
	}
	int max1=a[0],max2=a[k];
	for(i=1;i<k;i++)//找出次大值 
	{
   
		if(a[i]>max2)max2=a[i];
	}
	printf("最大值为:%d,次大值为:%d\n",max1,max2);
}
//两两元素段比较 
void two(int *a,int p,int t,int i)
{
   
	int j,temp,q=2*p;
	if(a[t]<a[t+p])
	{
   
		for(j=0;j<i;j++)temp=a[t+j],a[t+j]=a[t+p+j],a[t+p+j]=temp;
	temp=a[t+i];
	a[t+i]=a[t+p];
	a[t+p]=temp;
	}
	else if(a[t]==a[t+p])
	{
   
		int max=0,l;
		for(l=1;l<q;l++)
		{
   
			if(a[t]!=a[t+l]&&a[t+l]>max)
			{
   
				max=a[t+l];
			}
		}
		if(l==q&&max==0)max=a[t];
		a[t+i]=max;
		if(i==1
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值