top N 转发

topK问题的几种解法及C++实现_学习侠的博客-CSDN博客_c++ topk

 

topK问题是经典的算法问题,其大意是从一个序列中找出最小(大)的k个数,面对这个问题最简单的方法当然是先排序后取前k个数,但这样有些浪费时间,比较经典的方法是借助快排和堆排的思想。
注:为了方便讨论,以下均选择找出最小k个数。

解法1:快速选择
借助快排是思想,进行局部的排序。

void quickselect(vector<int>& input, int left, int right, int k) {
if (left >= right) {
return;
}
int num = input[left];
int i = left;
int j = right + 1;
while (i <= j) {
while (i < right && input[++i] < num) {}
while (j > 0 && input[--j] > num) {}
if (i <= j) {
swap(input[i], input[j]);
}
}
swap(input[left], input[j]);
if (k == j + 1) {
return;
}
else if (k < j + 1) {
quickselect(input, left, j - 1, k);
}
else {
quickselect(input, left, j - 1, k);
quickselect(input, i, right, k);
}
}

解法2:借助小顶堆
对数组建堆后执行k次提取最小值操作就行

//下滤
void PercDown(vector<int>& input, int i, int N) {
int Child;
while (2 * i + 1 < N) {
Child = 2 * i + 1;
if (Child + 1 < N && input[Child + 1] < input[Child])
++Child;
if (input[i] > input[Child])
swap(input[i], input[Child]);
else break;
i = Child;
}
}

//建堆(小顶堆)
void Heapsort(vector<int>& input) {
int N = input.size();
for (int i = N / 2 - 1; i >= 0; --i) {
PercDown(input, i, N);
}
}

//提取最小值
int DeleteMin(vector<int>& input) {
int N = input.size();
int MinElement = input[0];
int LastElement = input[N-1];
int i = 0, Child;
//下滤
while (2 * i + 1 < N) {
Child = 2 * i + 1;
if (Child + 1 < N && input[Child + 1] < input[Child])
++Child;
if (LastElement > input[Child])
input[i] = input[Child];
else break;
i = Child;
}
input[i] = LastElement;
input.pop_back();
return MinElement;
}

vector<int> topK(vector<int>& input, int k) {
Heapsort(input);
vector<int> res;
for (int i = 0; i < k; ++i) {
res.push_back(DeleteMin(input));
}
return res;
}

解法3:借助大顶堆
维持一个大小为k的大顶堆,当堆中元素不足k时直接插入元素,当堆中元素个数为k时,遍历到的元素若小于堆顶元素则替换堆顶元素再下滤,最后堆中的即为topk元素。

//下滤
void PercDown(vector<int>& input, int i, int N) {
int Child;
while (2 * i + 1 < N) {
Child = 2 * i + 1;
if (Child + 1 < N && input[Child + 1] > input[Child])
++Child;
if (input[i] < input[Child])
swap(input[i], input[Child]);
else break;
i = Child;
}
}

//建堆(大顶堆)
void Heapsort(vector<int>& input) {
int N = input.size();
for (int i = N / 2 - 1; i >= 0; --i) {
PercDown(input, i, N);
}
}

//插入
void Insert(vector<int>& res, int Element) {
res.push_back(Element);
int N = res.size();
if (N <= 1) return;
for (int i = N - 1; i > 0; i = (i - 1) / 2) {
if (res[(i - 1) / 2] < Element) {
swap(res[(i - 1) / 2], res[i]);
}
}
}

vector<int> topK(vector<int>& input, int k) {
vector<int> res;
for (int i = 0; i < input.size(); ++i) {
if (res.size() < k) {
Insert(res, input[i]);
}
else {
if (input[i] < res[0]) {
res[0] = input[i];
PercDown(res, 0, k);
}
}
}
return res;
}
————————————————
版权声明:本文为CSDN博主「学习侠」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43860854/article/details/108616568

posted @ 2021-06-18 10:35  caopf  阅读(36)  评论(0编辑  收藏  举报