堆排序在TOP K问题中的应用

本文介绍了一种高效算法,用于从大量整数中筛选出最小的K个数。通过构建并利用大顶堆数据结构,该算法实现了快速查找与替换,有效提升了处理效率。

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

问题

从数组中找出最大或者最小的k个数。

思路

以最小的k个数为例。可以使用一个大小为k的数组,然后依次遍历原始数据,当有元素比数组里的元素小时,就用这个数据将其替换出来。思路是对的,但是从大小为k的数组里面搜索最大元素的复杂度是O(n)。接下来优化一下,我们知道堆排序获得最大值(最小值)的复杂度是O(1),调整堆的复杂度是O(log n)。在海量数据处理的时候这个优化的效果是很明显的。

代码

题目描述:
输入n个整数,找出其中最小的K个数。

class BigHeap{//大顶堆,用于从k个数中获取最大值。
private:
    vector<int> data;//堆是完全二叉树,用数组存放
    int len;//堆中元素的个数
public:
    BigHeap(int n):len(n){}
    void push(int elem){//把元素放入堆中,然后调整堆
        int size = data.size();
        if(len < size)
            data.at(len) = elem;
        else
            data.push_back(elem);
        len += 1;
        int fa_idx = (len-2)/2;//新元素父节点下标
        int new_idx = len-1;//新元素的下标
        while(fa_idx >= 0){//每次讲新元素放到尾部,然后向上调整,直到满足条件或者到堆顶。
            if(data.at(new_idx) > data.at(fa_idx)){//因为是大顶堆,所以比父亲大就与父亲交换
                int tmp = data.at(new_idx);
                data.at(new_idx) = data.at(fa_idx);
                data.at(fa_idx) = tmp;
                new_idx = fa_idx;
                fa_idx = (fa_idx-1)/2;
            }
            else{
                break;
            }
        }
        printHeap();
    }
    int getMax(){//堆顶元素就是最大值
        if(len > 0)
            return data.at(0);
        else
            return 100000;
    }
    void printHeap(){//调试使用
        for(int i = 0; i < len; i++)
            cout << data.at(i) << " ";
        cout << endl;
    }
    void deleteMax(){//删除堆顶元素,然后调整堆
        if(len < 1)
            return;
        data.at(0) = data.at(len-1);//删除堆顶元素的方法是与最后的元素交换,然后减小元素个数len
        len -= 1;
        int fa_idx = 0;
        int lch_idx = (0+1)*2 - 1;
        int rch_idx = (0+1)*2;
        while(lch_idx < len){//调整堆的方法是向下调整,直到满足条件或者到堆尾
            int max_idx;
            if(rch_idx >= len){
                max_idx = lch_idx;
            }
            else{
                if(data.at(lch_idx) > data.at(rch_idx)){
                    max_idx = lch_idx;
                }
                else{
                    max_idx = rch_idx;
                }
            }
            if(data.at(fa_idx) < data.at(max_idx)){//向下调整是与孩子中最大的交换
                int tmp = data.at(fa_idx);
                data.at(fa_idx) = data.at(max_idx);
                data.at(max_idx) = tmp;
                fa_idx = max_idx;
                lch_idx = (max_idx + 1) * 2 -1;
                rch_idx = (max_idx + 1) * 2;
            }
            else{
                break;
            }
        }
        printHeap();
    }
};
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len = input.size();
        if(k > len){
            vector<int> ans;
            return ans;
        }

        BigHeap myBigHeap(0);
        int i;
        for(i = 0; i < k; i++){//现将前k个元素放入堆中
            myBigHeap.push(input.at(i));
        }
        while(i < len){//如果新元素比堆中最大元素小,则删除堆中最大元素,并将新元素入堆
            int max = myBigHeap.getMax();
            if(input.at(i) < max){
                myBigHeap.deleteMax();
                myBigHeap.push(input.at(i));
            }
            i++;
        }
        vector<int> ans(k, 0);//返回排序好的最小k个数
        for(i = k-1; i >= 0; i--){
            ans.at(i) = myBigHeap.getMax();
            myBigHeap.deleteMax();
        }
        return ans;
    }
};
### 使用堆排序解决Top-K问题 #### Top-K问题概述 Top-K问题是计算机科学领域中常见的一个问题,其目标是从给定的数据集中找到最大的K个元素或最小的K个元素。该问题可以通过多种算法实现,而堆排序是一种高效的解决方案[^1]。 #### 堆排序的核心原理 堆排序基于二叉堆结构,分为大根堆和小根堆两种形式。大根堆的特点是父节点大于等于子节点;小根堆则是父节点小于等于子节点。在解决问题时,通常会根据需求构建相应类型的堆。例如,在寻找前K个最大值时,可以使用小根堆来维护当前已知的最大K个数值[^2]。 #### 实现过程详解 以下是利用堆排序解决Top-K问题的具体方法: 1. **初始化阶段** 首先选取输入数组中的前K个元素构成初始的小根堆。这一步骤的时间复杂度为O(K),因为只需要对固定数量的元素进行建堆操作。 2. **遍历剩余元素并更新堆** 对于剩下的N-K个元素逐一处理:如果某个元素比当前堆顶(即堆中小的那个数)还要大,则将其替换掉堆顶位置上的旧值,并重新调整整个堆保持性质不变。此步每次执行需花费log K时间完成一次插入/删除动作,总共要重复(N-K)次因此总耗时约为 O((N−K)* log K)[^3]。 3. **最终结果提取** 经过上述两轮迭代之后得到的就是所需的top k项集合了。由于这些项目已经被存储在一个有效的优先队列里边所以可以直接读取出来作为答案返回即可。 下面给出一段Python版本代码展示如何应用这一思路去获取列表arr里的最高分成绩排名情况: ```python import heapq def find_top_k(nums, k): min_heap = nums[:k] heapq.heapify(min_heap) for num in nums[k:]: if num > min_heap[0]: heapq.heappushpop(min_heap, num) return sorted(min_heap , reverse=True) if __name__ == "__main__": arr = [7, 10, 4, 3, 20, 15] top_three_scores = find_top_k(arr, 3) print(top_three_scores) ``` 以上程序片段展示了怎样借助内置库`heapq`快速搭建起一个小顶堆用于筛选出指定长度内的最优解候选者们. #### 总结说明 综上所述可以看出采用堆这种数据结构确实能够很好地应对大规模数据下的top-k查询请求场景下效率表现优异的同时也具备良好的可扩展性和灵活性特点值得深入研究学习掌握这项技能对于提升个人技术水平有着重要意义.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值