方法一:使用最小堆。
1、用前k个元素建立一个最小堆;
2、遍历无序区域的元素,和堆顶元素对比,如果小于堆顶值,肯定不可能是前k个最大值;如果大于堆顶值,那么取代堆顶元素,做一次堆调整。
//最小堆的调整
void heap_adjust_for_maxK(int arr[], int s, int end)
{
//对堆进行一次调整
//方法:(以大顶堆为例)比较父节点和两个子节点的大小:如果父节点大,无需调整;
// 如果子节点大,那么和父节点交换;
// 继续调整该节点
//退出条件:left节点超出end;或者父节点比子节点大
int next = s;
int father = 0;
int left = 0;
int right = 0;
while( (left=father*2 + 1) <= end )
{
right = left + 1;
next = left;
if(right<=end && arr[right]<arr[left])
{
next = right;
}
if(arr[next] < arr[father])
{
int temp = arr[father];
arr[father] = arr[next];
arr[next] = temp;
}
else
{
break;
}
father = next;
}
return;
}
void maxK(int arr[], int num, int k)
{
if(k >= num)
{
return;
}
//创建前k个数的最小堆
for(int i=k/2-1; i>=0; i--)
{
heap_adjust_for_maxK(arr, i, k-1);
}
//从后面的非最小堆区域,遍历每个元素,与最小堆的对顶比较,如果小于堆顶元素,继续下一个;否则,取代堆顶元素,并做一次调整
for(int j=k; j<num; j++)
{
if(arr[j] > arr[0])
{
arr[0] = arr[j];
heap_adjust_for_maxK(arr, 0, k-1);
}
}
}
方法二:改进快速排序
int partion(int arr[], int left, int right)
{
int base = arr[left];
int i = left;
int j = right;
while(i < j)
{
while(j>i && arr[j]<=base)
j--;
while(j>i && arr[i]>=base)
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
arr[left] = arr[i];
arr[i] = base;
return i;
}
//思路:先对数组进行一次切分,此时基准点在mid位置,其左边都是大于基准的数据,
// 如果此时基准点在前k各数里面,则继续对mid之后的数组进行切分;
// 如果此时基准点在前k各数外面,则继续对mid左侧的数组进行切分
//终止条件:mid在k各数的最右边。
//这个条件一定会终止,这就是mid-1, mid+1的原因
void quick_sort(int arr[], int left, int right, int k)
{
int mid = 0;
if(left<right)
{
mid = partion(arr, left, right);
while(mid != k-1)
{
if(mid > k-1)
{
mid = partion(arr, left, mid-1);
}
else
{
mid = partion(arr, mid+1, right);
}
}
}
}
方法三:额外用一个k个节点的树存放
前两种方法都会对数组造成破坏,用这种方法则不会。
c++中可以使用multiset