蓝桥杯2014年C\C++组第5题-锦标赛


如果要在n个数据中挑选出第一大和第二大的数据(要求输出数据所在位置和值),使用什么方法比较的次数最少?我们可以从体育锦标赛中受到启发。8个选手的锦标赛,先两两捉对比拼,淘汰一半。优胜者再两两比拼...直到决出第一名。



第一名输出后,只要对黄色标示的位置重新比赛即可。


下面的代码实现了这个算法(假设数据中没有相同值)。


代码中需要用一个数组来表示图中的树(注意,这是个满二叉树,不足需要补齐)。它不是存储数据本身,而是存储了数据的下标。


第一个数据输出后,它所在的位置被标识为-1


锦标赛 示例代码

?
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//  pk(      a    ,  b,    2*n-1, 0,   b[0]);
//重新决出k号位置,v为已输出值
#include <stdio.h>
#include <stdlib.h>
void pk( int * a, int * b, int n, int k, int v)
{
     int k1 = k*2 + 1;
     int k2 = k1 + 1;
     
     if (k1>=n || k2>=n){
         b[k] = -1;
         return ;
     }
     
     if (b[k1]==v)
         pk(a,b,n,k1,v);
     else
         pk(a,b,n,k2,v);
     
     //重新比较
     if (b[k1]<0){
         if (b[k2]>=0)
             b[k] = b[k2];
         else
             b[k] = -1;
         return ;
     }
     
     if (b[k2]<0){
         if (b[k1]>=0)
             b[k] = b[k1];
         else
             b[k] = -1;
         return ;
     }
     
     if (a[b[k1]] > a[b[k2]]) //填空
         b[k] = b[k1];
     else
         b[k] = b[k2];
}
 
//对a中数据,输出最大,次大元素位置和值
void f( int * a, int len)
{
     int n = 1;
     while (n<len) n *= 2; // manshugeshu
     
     int * b = ( int *) malloc ( sizeof ( int *) * (2*n-1));
     int i;
     for (i=0; i<n; i++){
         if (i<len)
             b[n-1+i] = i;
         else
             b[n-1+i] = -1;
     }
     
     //从最后一个向前处理
     for (i=2*n-1-1; i>0; i-=2){
         if (b[i]<0){
             if (b[i-1]>=0)
                 b[(i-1)/2] = b[i-1];
             else
                 b[(i-1)/2] = -1;
         }
         else {
             if (a[b[i]]>a[b[i-1]])
                 b[(i-1)/2] = b[i];
             else
                 b[(i-1)/2] = b[i-1];
         }
     }
     
     //输出树根
     printf ( "%d : %d\n" , b[0], a[b[0]]);
     
     //值等于根元素的需要重新pk
     pk(a,b,2*n-1,0,b[0]);
     
     //再次输出树根
     printf ( "%d : %d\n" , b[0], a[b[0]]);
     
     free (b);
}
 
 
int main()
{
     int a[] = {54,55,18,16,122,17,30,9,58};
     f(a,9);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值