top K问题是这样的,给定一组任意顺序的数,假设有n个。如何尽快地找到它们的前K个最大的数?
首先,既然是找前K个最大的数,那么最直观的办法是,n个数全部都排序,然后挑出前K个最大数。但是这样显然做了一些不必要的事儿。
利用堆这种数据结构,借助前文《排序算法整理(5)堆排序》中谈到的维护堆的函数, min_heapify( ),就可以轻松解决top K问题。
主要步骤如下:
step 1. 随意选出K个数,挑出这K个数的最小的数。这个过程可以用最小堆完成。
step 2. 在剩下的n – K个数中,挑出任意一个数m,和最小堆的堆顶进行比较,如果比最小堆的堆顶大,那么说明此数可以入围前K的队伍,于是将最小堆的堆顶置为当前的数m。
step 3. 调整最小堆。时间复杂度为Olg(K),由于K是constant(常数级别),所以时间复杂度可以认为是常数级别。
step 4. 重复进行step 2 ~ step 3,直到剩下的n – K个数完成。进行了n –constant次,时间复杂度为O(n lgK).
核心代码如下:
void top_k(int * p_arr, int length,int k, int * p_res)
{
int * adjusted_array = new int[k+1];
adjusted_array[0]=0;
for(int i=0;i
完整实现代码如下。有heap.h和heap.cpp和main.cpp这3个文件。
这是heap.h
//heap.h文件
#include
#include
inline int l_child(int i);
inline int r_child(int i);
inline int parent(int i);
static void max_heapify_recur(int * p_arr,int i,int heap_size);
static void max_heapify_norecur(int * p_arr,int i,int heap_size);
static void min_heapify_recur(int * p_arr,int i,int heap_size);
void build_heap_max(int * p_arr,int heapsize);
void build_heap_min(int * p_arr,int heapsize);
void heap_sort_max(int * p_arr, int length);
void heap_sort_min(int * p_arr, int length);
void top_k(int * p_arr, int length, int k, int * p_res);
//heap.cpp文件
#include "heap.h"
inline int l_child(int i)
{
return 2*i;
}
inline int r_child(int i)
{
return 2*i+1;
}
inline int parent(int i)
{
return i/2;
}
static void max_heapify_recur(int * p_arr,int i,int heap_size)
{
//if(i>heap_size/2)//叶节点不需要进行堆建立
// return;
int l = l_child(i);
int r = r_child(i);
int largest = 0;
if ( (l<= heap_size) && (p_arr[l]>p_arr[i]) )
largest = l;
else
largest = i;
if( (r<=heap_size) && (p_arr[r]>p_arr[largest]) )
largest = r;
// printf("i:%d,largest:%d,array[i]:%d,array[largest]:%d\n",i,largest,p_arr[i],p_arr[largest]);
if (largest != i) {
int temp = p_arr[i];
p_arr[i] = p_arr[largest];
p_arr[largest] = temp;
max_heapify_recur(p_arr, largest,heap_size);
}
return;
}
static void max_heapify_norecur(int * p_arr,int i,int heap_size)
{
while(i<=heap_size/2) {
int l = l_child(i);
int r = r_child(i);
int largest = 0;
if ( (l<= heap_size) && (p_arr[l]>p_arr[i]) )
largest = l;
else
largest = i;
if( (r<=heap_size) && (p_arr[r]>p_arr[largest]) )
largest = r;
// printf("i:%d,largest:%d,array[i]:%d,array[largest]:%d\n",i,largest,p_arr[i],p_arr[largest]);
if (largest != i) {
int temp = p_arr[i];
p_arr[i] = p_arr[largest];
p_arr[largest] = temp;
i=largest;
}
}
return;
}
static void min_heapify_recur(int * p_arr,int i,int heap_size)
{
//if(i>heap_size/2)//叶节点不需要进行堆建立
// return;
int l = l_child(i);
int r = r_child(i);
int smallest = 0;
if ( (l<= heap_size) && (p_arr[l]=1;i-- )
{
max_heapify_recur(p_arr,i,heapsize);
}
return;
}
void build_heap_min(int * p_arr,int heapsize)
{
int start=heapsize/2;
for(int i = start;i>=1;i-- )
{
min_heapify_recur(p_arr,i,heapsize);
}
return;
}
void heap_sort_max(int * p_arr, int length)
{
int * adjusted_array = new int[length+1];
adjusted_array[0]=0;
for(int i=0;i=1;heap_size--) {
int temp = adjusted_array[1];
adjusted_array[1] = adjusted_array[heap_size];
adjusted_array[heap_size] = temp;
max_heapify_recur(adjusted_array,1,heap_size-1);
}
for(int i=0;i=1;heap_size--) {
int temp = adjusted_array[1];
adjusted_array[1] = adjusted_array[heap_size];
adjusted_array[heap_size] = temp;
min_heapify_recur(adjusted_array,1,heap_size-1);
}
for(int i=0;i
//main.cpp文件
#include "heap.h"
//int src_arr[11] = {-1,1,2,3,4,5,6,7,8,9,10};
//int src_arr[21] = {-1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
//int src_arr[10] = {1,2,3,4,5,6,7,8,9,10};
//int src_arr[10] = {10,9,8,7,6,5,4,3,2,1};
int src_arr[10] = {8,4,6,3,5,2,1,7,9,10};
int src_arr_top_k[10] = {8,4,6,3,5,2,1,7,9,10};
void print_arr(int *p_arr, int length)
{
printf("array is:");
for(int i =1;i<=length;i++) //为了方便,这里跳过p_arr[0],相当于数组下标从1开始计数。
printf("\t%d",p_arr[i]);
printf("\n");
}
void print_arr_2(int *p_arr, int length)
{
printf("array is:");
for(int i =0;i
输出结果如下