锦标赛法计算最大值与次大值
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