最近在看一个题目:给定一个无序的整型数组,求出其中最大的K个值。
这个题的解法很多,最普遍的就是排序,时间复杂度就是O(nlogn)+O(n)。
还可以根据快速排序的思想,分治与递归的求解最大的K个值。基本思想是:在每一次排序后,会有一个数字到达了它的有序的位置,这个数字之前所有的元素都小于它,它后面的所有的元素都大于它。可以用Sa表示前面的元素,Sb表示后面的元素。如果K>Num(Sb)(Num表示数组中元素的个数),那么就输出Sb,然后递归在Sa中寻找剩余的K-Num(Sb)。如果K<Num(Sb),那么就递归在Sb中寻找K个最大的值。这样递归下去,不断把问题分解成更小的问题,平均时间复杂度为O(N*logK),算法得到了进一步改进。
以下是这个思想的代码:
void fun(int data[],int low,int hight,int k)
{
int i = low;
int j = hight;
int x = data[low];
while(j > i)
{
while(data[j] > x && j > i)
j--;
if(i < j)
{
data[i] = data[j];
i++;
}
while(data[i] < x && j > i)
i++;
if(i < j)
{
data[j] = data[i];
j--;
}
}
data[i] = x;
int pos = i;
if(k > hight - pos )
{
for(int n = pos + 1; n <= hight; n++)
cout << data[n] << " ";
fun(data,low,pos,k-hight+pos);
}
else if(k < hight - pos)
{
fun(data,pos+1,hight,k);
}
else
{
for(int n = pos+1; n <= hight; n++)
cout << data[n] << " ";
}
}
如果,数组很大时,比如数组有1亿个元素呢,如果还用以上算法就会显得非常的慢。我们可以用堆来求其中的最大的K个值。
思想:构造一个小根堆,因为根是最小的,然后将原数组中剩余的元素与堆的根比较,如果heap_value > data[i],那么继续遍历数组, 如果heap_value < data[i],那么将heap_value的值改为data[i],并调整堆,使新堆满足小根堆。这样只需遍历原数组一遍就可以找到K个最大值,这K个最大的值就存储在堆中。
顺便回忆一下小根堆是怎么来构建和调整的。设堆的节点数为n,因为堆是一个完成二叉树,那么最后一个非叶节点就是n/2。从这个节点开始来构建堆。设当前节点为p,那么q = 2 * q + 1,q就是左子树,q+1就是右子树。如果左子树或者右子树的值比父节点的值小,那么和父节点交换。然后看子树的子树是否需要调整,如果不需要调整,那么p--,开始向上走,这样最后便得到一个小根堆,大根堆同理。
下面是求K个最大值,用小根堆解的代码:
void swap2(int &a,int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void CreateHeap(int data[],int K)
{
int p = K/2 - 1;
while(p >= 0 && p < K)
{
int q = 2 * p + 1;
if(q < K)
{
if(q < K - 1 && data[q+1] < data[q])
q = q + 1;
if(data[q] < data[p])
{
swap2(data[p],data[q]);
int n = 2 * q + 1;
if(n < K)
{
if((data[q] > data[n] )||((n < K-1) && (data[q] > data[n+1])))
{
p = q;
}
}
else
p--;
}
else
p--;
}
}
}
void FindMaxK2(int data[],int len,int K)
{
int *heap = new int[K];
// 初始化堆
for(int i = 0;i < K; ++i)
{
heap[i] = data[i];
}
// 调整成小根堆
CreateHeap(heap,K);
// 开始将剩余元素与堆根比较,并调整堆
for(int i = K; i < len; ++i)
{
int X = data[i];
if(X > heap[0])
{
heap[0] = X;
CreateHeap(heap,K);
}
}
for(int i = 0; i < K; ++i)
cout << heap[i] << " ";
delete []heap;
heap = 0;
}