使用堆排序来求解 数组维持k个数 新来的元素和根进行比较 找k个最大值 建小堆 此时堆顶为最小值 当新来的元素比堆顶元素还要小 直接抛弃就可以了 因为不可能是最大值 否则 堆顶为新来的元素 替换堆顶在进行重新调整 (找最小值同样原理) 调整的时候根据最后一个父节点开始调整 遵循从下到上 从右向左的原理 时间复杂度为:O(nlogk) 不会修改输入的数组
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//寻找最大的k个数 建立k个小顶堆
void HeapAdjust(vector<int>&res,int pos) //根
{
for(int i=2*pos+1;i<res.size();i=2*i+1)
{
if((i<res.size()-1)&&(res[i]>res[i+1])) //i<res.size()-1 防止越界
i++; //i一直++ 左一直大于右 循环出来
//不满足条件 将这个小的值和根比
if(res[i]>res[pos]) break; //此时根是最小的 不变
swap(res[i],res[pos]); //否则孩子比根还小 交换孩子与根
pos = i;
}
}
void topK(vector<int>&vec,int k)
{
if(vec.size()<k) return;
vector<int>res;
res.resize(k); //设置数组中的个数为k
for(int i=0;i<k;i++)
res[i] = vec[i];
for(int i=res.size()/2-1;i>=0;i--)
HeapAdjust(res,i);
for(int i=k;i<vec.size();i++)
{
if(vec[i]>res[0])
{
res[0] = vec[i];
HeapAdjust(res,0);
}
}
for(auto i:res)
cout<<i<<" "<<endl;
}
int main()
{
vector<int>vec;
vec.push_back(38);
vec.push_back(25);
vec.push_back(97);
vec.push_back(1);
vec.push_back(2);
topK(vec,3);
system("pause");
return 0;
}
找k个最小值
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//找k个最小值 建大根堆
void Adjust(vector<int>&res,int pos) //根
{
for(int i=2*pos+1;i<res.size();i++)
{
if((i<res.size()-1)&&(res[i]<res[i+1])) //i<res.size()-1 防止越界
i++; //不满足i++说明左边比右边大
if(res[pos]<res[i]) //res[pos]是根的值 建大根堆
{
swap(res[pos],res[i]);
}
else
break;
pos = i;
}
}
void top_k(vector<int>&vec,int k)
{
if(vec.size()<k) return;
vector<int>res; //设置最终的数组 元素容量为k
res.resize(k);
for(int i=0;i<k;i++)
res[i] = vec[i];
//调整堆顶 res[0] 为最大值
for(int i=res.size()/2-1;i>=0;i--)
{
Adjust(res,i); //最后一个根开始调整
}
for(int i=k;i<vec.size();i++)
{
if(vec[i]<res[0])
{
res[0] = vec[i];
Adjust(res,0);
}
}
for(auto i:res)
cout<<i<<" "<<endl;
}
int main()
{
vector<int>vec;
vec.push_back(3);
vec.push_back(38);
vec.push_back(0);
vec.push_back(9);
vec.push_back(1);
top_k(vec,4);
system("pause");
return 0;
}
或者使用优先队列
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<functional> //greater的头文件
using namespace std;
//优先队列 底层是堆实现的 求前k个最大值 最大值 建小堆
vector<int>topk(vector<int>&vec,int k)
{
priority_queue<int,vector<int>,greater<int>>heap; //less大堆 greater小堆 优先队列默认是大堆
for(int i=0;i<k;i++)
{
heap.push(vec[i]);
if(heap.size()>k)
heap.pop();
}
vector<int>res;
while(heap.size())
{
res.push_back(heap.top());
heap.pop();
}
return res;
}
int main()
{
vector<int>res;
vector<int>vec;
vec.push_back(5);
vec.push_back(9);
vec.push_back(100);
vec.push_back(1);
vec.push_back(0);
res = topk(vec,3);
for(auto i:res)
cout<<i<<endl;
system("pause");
return 0;
}
快排思想 :找一个标准值 将比标准值小的都放在左侧 比标准大的都放在右侧
最小的k个数 :如果我们基于第k个数来调整 比第k个数小的都放在左侧 比第k个数大的都放在右侧 因为我们每次查找一次 都会选择出一个更小的值 所以最后遍历一遍数组 时间复杂度为O(n) 但是前提是我们对传入的数组进行了修改
#include<iostream>
#include<vector>
using namespace std;
//最小的k个数 基于快排的思想
int Search(vector<int>&vec,int nlow,int nhigh)
{
if(vec.empty()||nlow>nhigh) return -1;
int nsmall = nlow-1;
for(nlow;nlow<nhigh;nlow++)
{
if(vec[nlow]<vec[nhigh])
{
if(++nsmall!=nlow) //因为异或有个条件 是不可以操作同一块空间
{ //其实是nsmall先加加 然后跟nlow进行比较
vec[nsmall] = vec[nsmall]^vec[nlow];
vec[nlow] = vec[nsmall]^vec[nlow];
vec[nsmall] = vec[nsmall]^vec[nlow];
}
}
}
if(++nsmall!=nhigh)
{
vec[nsmall] = vec[nsmall]^vec[nhigh];
vec[nhigh] = vec[nsmall]^vec[nhigh];
vec[nsmall] = vec[nsmall]^vec[nhigh];
}
return nsmall;
}
vector<int>topk(vector<int>&vec,int k)
{
vector<int>res;
if(vec.size()<k) return res;
int nlow = 0;
int nhigh = vec.size()-1;
int index = Search(vec,nlow,nhigh);
while(index!=k-1) //以第k个为基准
{
if(index>k-1) //操作的都是下标 在第k个值后面了
{
nhigh = index-1;
index = Search(vec,nlow,nhigh);
}
else //在第k个值前面
{
nlow = index+1;
index = Search(vec,nlow,nhigh);
}
}
for(int i=0;i<k;i++)
res.push_back(vec[i]);
return res;
}
int main()
{
vector<int>res;
vector<int>vec;
vec.push_back(3);
vec.push_back(1);
vec.push_back(2);
vec.push_back(4);
vec.push_back(5);
res = topk(vec,2);
for(auto i:res)
cout<<i<<endl;
system("pause");
return 0;
}