当前位置:首页 » 《随便一记》 » 正文

数据结构与算法_大数据处理_topK问题的两种求解方法

6 人参与  2022年11月15日 17:10  分类 : 《随便一记》  评论

点击全文阅读


这篇笔记记录求大数据topk的两种方法,分别是大小二叉堆法和快速分割法,下面依次详解这两种方法的过程。

1 大/小根堆法

利用大根堆过滤前top k小的数据**;小根堆过滤前top k大的数据**;
下面用大根堆求前k个小元素为例。

思想:
把大根堆堆顶的大值不断的淘汰,放入小值。先构建k个元素的大小堆(比如k=3,就是求数列中前3个元素),然后用数列中的元素依次与堆顶元素比较,如果大于或者小于堆顶元素,就进行出堆调整;最后再进行入堆调整。过程
先用数列中前k个元素构建一个堆,比如构建一个大根堆。新元素与堆顶元素比较,大于堆顶元素就进行下一个元素;如果新元素比堆顶元素小,堆顶元素先出堆,然后将新元素加入到堆中
在这里插入图片描述

代码

#include <iostream>#include <vector>#include <time.h>#include <queue>#include <functional>using namespace std;int main(){vector<int> vec;srand(time(NULL));for (int i = 0; i < 10; i++){vec.push_back(rand() % 100);cout << vec[i] << " ";}cout << endl;// 求vec中值最小的前5个元素priority_queue<int> maxheap;int k = 5;// 前5个元素入堆for (int i = 0; i < 5; i++){maxheap.push(vec[i]);}// 遍历剩余元素,直到最后for (int i = 5; i < vec.size(); i++){if (maxheap.top() > vec[i]){maxheap.pop();maxheap.push(vec[i]);}}// 输出结果  while (!maxheap.empty()){cout << maxheap.top() << " ";maxheap.pop();}cout << endl;

求出序列中值最大的前k个元素

priority_queue<int, vector<int>, greater<int>> minheap;// 前5个元素入堆for (int i = 0; i < 5; i++){minheap.push(vec[i]);}// 遍历剩余元素,直到最后for (int i = 5; i < vec.size(); i++){if (minheap.top() < vec[i]){minheap.pop();minheap.push(vec[i]);}}// 输出结果  while (!minheap.empty()){cout << minheap.top() << " ";minheap.pop();}

2 快排分割法

背景: 实际工作场景中经常遇到求topk的问题,比如找出最近人们搜索最多的商品,最多的应用等,多属于topk的问题,除了上面的利用大小根堆来求解topk问题之外,还可以利用快速排序思想求解topk问题。
**算法思想:**利用快速排序算法思想,判断快排分割函数每次返回的Pos值,如果pos值等于topk就直接返回,这样数组中从0到pos位置求出的就是前topk;如果pos大于或者小于topk,就继续求解。
算法步骤:
利用了快速排序的步骤。

在这里插入图片描述
在这里插入图片描述
算法性能分析:
平均时间复杂度:第一次找出一半的元素,第二次递归分割直达pos = K-1 ;一共N个元素,平均结果如下:
O(n)=N + N/2 +N/4 + … + 1 = 2N = O(n)
**最坏情况下时间复杂度:如果原始数列是有序的,比如从小到大的排列的,这时候求最大的top1时候,时间复杂度如下:
N +(N-1) + (N-2) +(N -3) + … + 1 = O(N2)=**O(n2)

在这里插入图片描述

代码

#include <iostream>#include <functional>#include <time.h>using namespace std;/** 功能:快排分割函数。每次递归时,将数组中的数据分割为两组,分别比val大的分成一组,比val小的分成一组。** 参数:*arr[]: 要分割的数组*begin: 数组开始下标*end  : 数组的结束位置*/int Partition(int arr[], int begin, int end){int val = arr[begin];int i = begin;int j = end;while (i < j){while (i < j && arr[j] > val){j--;}// 如果找到右边的值大于begin,就进行下面的操作,把比val大的放在if (i < j){arr[i] = arr[j];i++;}while (i < j && arr[i] < val){i++;}if (i < j){arr[j] = arr[i];j--;}}arr[i] = val;return i;}/** 功能:求出前topk** 参数:**arr : 求topk的数组*begin: 数组开始下标*end  : 数组的结束位置*k    : 要求解的前topk。*/void SelectTopK(int *arr, int begin, int end ,int k){int pos = Partition(arr, begin, end);if (pos == k - 1) // 如果上面分割好的pos中间位置,刚好等于topk,直接返回。{return;}else if (pos > k - 1)  // 假如返回 5  而要找topk=3,则继续快排分割。{SelectTopK(arr, begin, pos - 1, k);}else{SelectTopK(arr, begin, pos - 1, k);}}int main(){int arr[] = { 64,45,52,80,66,68,0,2,18,75 };int size = sizeof arr / sizeof arr[0];// 假如求最小的topK,最后返回数组中的topk个元素。int k = 3;SelectTopK(arr, 0, size - 1,k);for (int i = 0; i < k; i++){cout << arr[i] << " ";}cout << endl;system("pause");return 0;}

点击全文阅读


本文链接:http://zhangshiyu.com/post/48582.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1