队列是一种先进先出的结构,但优先级队列需要对后挤进去的数据进行排序,如果足够大的话会排至队首。它可以用来维护一堆数据中最大(最小)的N个数据,在这里用大顶堆(完全二叉树)来实现不停输入整数时找出K个最小的数,通过与堆顶的比较,决定是否顶替堆顶并再次排序。这也是为了给KD树求K近邻做个铺垫~
大顶堆在数组中的表现是数组下标n是下标2n与2n+1的父节点,同时2n的节点大于它的兄弟节点,因此在有数据顶替堆顶之后,再依次与其子节点比较,若有需要则替换。这样每一次维护的平均时间复杂度是nlog(n)。
开心写代码:
#include <iostream>
using namespace std;
int *a;//初始化数组
//交换位置
void swapData(int a[],int i,int j)
{
int temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//维护大顶堆
void reorderQueue(int a[],int n)
{
int q;
//检查从堆顶沉下来的数据是否需要与子节点交换
for(int i = 1;i < n/2+1;i++)
{
q=2*i;
if(q+1 > n) break;
if(a[q] < a[q+1]) swapData(a,q,q+1);
if(a[i] < a[q]) swapData(a,i,q);
}
}
void insertData(int a[],int insertInt,int n,int K)
{
if(n <= K)
{
a[n]=insertInt;
reorderQueue(a,n);
}
else if(n > K && insertInt < a[1])
{
a[1]=insertInt;
reorderQueue(a,K);
}
else
{
cout<<"a too big integer"<<endl;
}
}
int main()
{
int K;//从数据中找最小的K个数
cout<<"Please input K"<<endl;
cin >> K;
int *a = new int[K+1];
a[0]=-1;
cout<<"Please input data"<<endl;
int n = 1;
int insertInt;
while(cin>>insertInt)
{
insertData(a,insertInt,n,K);
++n;
for(int i = 1;i < K+1;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
delete a;
return 0;
}
通过堆排序,可以在消耗较少内存的情况下找到大量数据中最大(小)的若干数据。