锦标赛(n个数中求第一和第二大的数)

如果要在n个数据中挑选出第一大和第二大的数据(要求输出数据所在位置和值),使用什么方法比较的次数最少?我们可以从体育锦标赛中受到启发。

如图【1.png】所示,8个选手的锦标赛,先两两捉对比拼,淘汰一半。优胜者再两两比拼…直到决出第一名。

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

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

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

第一个数据输出后,它所在的位置被标识为-1
蓝桥杯上的一个填空题,感觉想法很好。
用一个b数组来存放这些数的下标,为空的地方就赋值为-1,然后通过左右子树不断的比较,将大数放到父亲节点,一直到根节点,先输出最大数,然后进行第二次比较,从根节点一直往下,把较大的数继续放到父亲节点,把第一次的最大数覆盖,一直到根节点,再输出第二大的数。
比较的过程
代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib> 
using namespace std; 
void pk(int* a, int* b, int n, 
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
锦标赛方法是一种基于树形结构的排序算法,其基本思想是通过比较个元素,将较小的元素不断向上比较,最终得到最小元素。在锦标赛方法,我们可以通过构建一棵完全二叉树来实现对序列的排序。 对于一个长度为n的序列,我们可以构建一棵完全二叉树,其叶子节点为序列的各个元素。在构建树的过程,每个节点都是其左右子树最小元素的较小值。最终根节点即为整个序列最小值。 为了第二大元素,我们可以在树的构建过程记录每个节点的次小值,即每个节点的左右子树除了最小值之外的最小值。对于根节点来说,次小值即为整个序列第二小元素。 具体实现过程如下: 1. 构建一棵完全二叉树,并将序列的元素作为叶子节点插入树。 2. 从下往上对每个节点进行处理,计算其次小值。对于一个节点来说,其次小值为其左右子树除了最小值外的最小值。 3. 最终根节点的次小值即为整个序列第二小元素。 4. 统计比较次,即每次比较个元素时的次。 下面给出使用锦标赛方法第二大元素的 Python 代码实现: ```python import math def build_tree(arr): n = len(arr) m = 2 * n - 1 tree = [0] * m for i in range(n): tree[m-n+i] = arr[i] for i in range(m-n-1, -1, -1): tree[i] = min(tree[2*i+1], tree[2*i+2]) return tree def find_second_largest(tree): n = (len(tree)+1) // 2 cur = 0 compare_count = 0 while cur < n-1: left = 2 * cur + 1 right = 2 * cur + 2 if tree[left] < tree[right]: cur = left else: cur = right compare_count += 1 second = math.inf for i in range(n, len(tree)): if tree[i] < second and tree[i] > tree[cur]: second = tree[i] compare_count += 1 return second, compare_count arr = [3, 5, 2, 8, 1, 9, 4, 7, 6] tree = build_tree(arr) second, compare_count = find_second_largest(tree) print('Second largest element:', second) print('Number of comparisons:', compare_count) ``` 在上面的代码,我们首先通过 `build_tree` 函构建了一棵完全二叉树,并将原序列的元素作为叶子节点插入树。然后,我们从根节点开始,依次比较其左右子树最小值,并记录比较次。最终,我们得到了根节点及其次小值,即整个序列最小值和次小值。我们将次小值作为第二大元素返回,并统计比较次。 在上面示例数据 `[3, 5, 2, 8, 1, 9, 4, 7, 6]` 第二大元素为 `8`,比较次为 `13`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值