Python 利用中间值求TopK 算法

本文深入探讨了Python中实现TopK算法的策略,通过寻找中间值来高效地筛选出数据集中最大的K个元素,避免了全排序的高计算成本,特别适合处理大规模数据集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法思想

首先我们要思考,我要做什么?解决什么问题
TopK问题,找出一组数据中的前K个最大值或者最小值,这个数据是否重复?要做去重处理?
ok 我们明确我们做什么了 ,那介绍的python处理的topK 算法过程是怎么样的呢?
~~要找出前K个最大值最小值我们可以用排序来做,然后用切片去完事了 ~~ 如果用排序那就没必要引入topK 了,当数据强大的时候选取TopK 可以省略很多排序的计算,至于有多优化自己去思考下,就比如排列组合的C,A的区别,一个是抽取,一个是抽取并排列…

以下以找出TopK 的最大值为例,最小值的可以自己修改一下下就可以

介绍的算法思想是利用中间值,将数列分为三部分 ,
【比中间值大的列表】,中间值,【比中间值小的列表】

那么我们当比较
【比中间值大的列表】的个数 == k
的时候就可以得出前K个最大值了,因此

重点就是找出这个中间值

如何找出中间值

以列表的第一个数开始为中间值,拆分为三部分
if 【比中间值大的列表】的个数 == k:return 中间值 #程序出口,结束。

if 【比中间值大的列表】的个数 < k
·····继续在【比中间值小的列表】找
·····K - 【比中间值大的列表】的个数 -1 个数
(为什么要减一,1是前一次的中间值,分的三部分,前部分后部分都没有包含中间值,因此…)
if 【比中间值大的列表】的个数 > k
…也就是说比中间值大的列表比K还大,那就在这个列表中继续找就行

结合代码和注释看

,如果要找最小值,只需要改一下就ok ,还可以设置一个布尔值的输入,来做前K个最大值最小值

#2019 11 04
#author 半斤地瓜烧
#TopK 算法,找出序列中前K个最大值的

#输入一个seq
# 输出以seq[0]为中间值 划分的三个部分,中间值,比这个值大的seq ,比这个值小的seq,
# 即splitNum,theBig,theSmall
def Split_Seq(seq):
    splitNum = seq[0]
    seq = seq[1:]#两个部分都不包含中间值,因此切片去除seq[0]
    theBig = [x for x in seq if x >= splitNum]
    theSmall = [x for x in seq if x < splitNum]
    return splitNum,theBig,theSmall

#找出中间值
def topKNum(seq,k):
    splitNum, theBig, theSmall = Split_Seq(seq)
    theBigLen = len(theBig)
    
    if  k == theBigLen:
        return splitNum#出口,返回这个中间值,
    # 为什么不直接返回thebig?因为存在递归的原因thebig 不是在初始的seq找出来的
    #需要重新Split,即可,读者自己思考

    # 大值的列表中还未够K个数的情况,
    if k > theBigLen:
        return topKNum(theSmall,k-theBigLen-1)

    # 大值的列表中大于K个数的情况
    return topKNum(theBig,k)

#由中间值找出TopK个值,<list>
def getTopK(seq,k):
    
    return [i for i in seq if i > topKNum(seq, k)]


if __name__ == '__main__':
    alist = [7, 3, 5, 1,885,234,2211,222,22, 2, 11, 2, 115]
    print("===为了验证,引入排序观看===", sorted(alist,reverse= True))

    print(getTopK(alist, 3))
### 快速选择算法实现 Top K 元素 快速选择算法是一种基于分治法的高效算法,用于寻找无序列表中的第 \(k\) 大或第 \(k\) 小元素。它的时间复杂度平均为 \(O(N)\),但在最坏情况下可能达到 \(O(N^2)\)[^3]。 以下是使用 Python 实现快速选择算法来获数组中前 \(K\) 个最大元素的过程: #### 算法核心逻辑 快速选择的核心在于利用类似于快速排序的思想,在一次划分操作后只处理包含目标值的那一部分数据。具体来说: - 随机选一个枢轴(pivot),并将其作为基准。 - 对数组进行分区操作,使得小于 pivot 的元素位于左侧,大于等于 pivot 的元素位于右侧。 - 如果当前 partition 返回的位置正好是第 \(N-K\) 位,则该位置上的数即为第 \(K\) 大的数;否则继续递归地在左半区或右半区执行上述过程直到找到目标位置。 #### 代码实现 下面是一个完整的 Python 实现示例: ```python import random def find_kth_largest(nums, k): """ 使用快速选择算法找出数组中的第 k 大元素 :param nums: List[int], 输入数组 :param k: int, 要找的第 k 大元素 :return: int, 第 k 大元素 """ def partition(left, right, pivot_index): pivot = nums[pivot_index] # 将 pivot 移动到右边 nums[pivot_index], nums[right] = nums[right], nums[pivot_index] store_index = left for i in range(left, right): if nums[i] > pivot: # 寻找第 k 大,因此比较条件为 > nums[store_index], nums[i] = nums[i], nums[store_index] store_index += 1 # 将 pivot 放回中间 nums[right], nums[store_index] = nums[store_index], nums[right] return store_index def select(left, right, k_smallest): if left == right: return nums[left] pivot_index = random.randint(left, right) pivot_index = partition(left, right, pivot_index) if k_smallest == pivot_index: return nums[k_smallest] elif k_smallest < pivot_index: return select(left, pivot_index - 1, k_smallest) else: return select(pivot_index + 1, right, k_smallest) return select(0, len(nums) - 1, k - 1) # 测试函数 nums = [3, 2, 1, 5, 6, 4] k = 2 result = find_kth_largest(nums, k) print(f"The {k}th largest element is {result}") ``` 此代码实现了 `find_kth_largest` 函数,能够返回输入数组中的第 \(k\) 大元素。其中随机化 pivot 的选择可以有效降低遇到最差情况的概率。 #### 性能分析 - **时间复杂度**: 平均时间为 \(O(N)\),因为每次只需要处理一半的数据量。然而,在极端情况下(如已经有序且始终选错 pivot),可能会退化至 \(O(N^2)\)[^3]。 - **空间复杂度**: 主要是递归调用栈的空间消耗,通常为 \(O(\log N)\)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值