排序算法整理(6)堆排序的应用,top K 问题
来源:互联网 发布:html导航页面源码 编辑:程序博客网 时间:2024/06/06 14:28
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<k;i++) //构建前k名构成的堆。adjusted_array[i+1]=p_arr[i];build_heap_min(adjusted_array,k);for(int j=k;j<length;j++){if(adjusted_array[1]<p_arr[j]){adjusted_array[1]=p_arr[j];min_heapify_recur(adjusted_array,1,k);}}for(int m=1;m<=k;m++)p_res[m-1]=adjusted_array[m];delete [] adjusted_array;//拷贝给p_res后再删除adjusted_arrayreturn;}
完整实现代码如下。有heap.h和heap.cpp和main.cpp这3个文件。
这是heap.h
//heap.h文件#include <stdio.h>#include <stdlib.h>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
//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;elselargest = 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;elselargest = 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]<p_arr[i]) ) smallest = l;elsesmallest = i;if( (r<=heap_size) && (p_arr[r]<p_arr[smallest]) )smallest = r;//printf("i:%d,largest:%d,array[i]:%d,array[largest]:%d\n",i,largest,p_arr[i],p_arr[largest]);if (smallest != i) {int temp = p_arr[i]; p_arr[i] = p_arr[smallest];p_arr[smallest] = temp;min_heapify_recur(p_arr, smallest, heap_size);}return;}void build_heap_max(int * p_arr,int heapsize){int start=heapsize/2;for(int i = start;i>=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<length;i++) //构建下表从1开始的数组作为adjusted_array,方便进行堆排序adjusted_array[i+1]=p_arr[i];build_heap_max(adjusted_array,length);for(int heap_size=length;heap_size>=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<length;i++) //将adjusted_array还原为输入数组p_arr[i]=adjusted_array[i+1];delete [] adjusted_array;return;}void heap_sort_min(int * p_arr, int length){int * adjusted_array = new int[length+1];adjusted_array[0]=0;for(int i=0;i<length;i++) //构建下表从1开始的数组作为adjusted_array,方便进行堆排序adjusted_array[i+1]=p_arr[i]; build_heap_min(adjusted_array,length);for(int heap_size=length;heap_size>=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<length;i++) //将adjusted_array还原为输入数组(也是输出数组)p_arr[]p_arr[i]=adjusted_array[i+1];delete [] adjusted_array;return;}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<k;i++) //构建前k名构成的堆。adjusted_array[i+1]=p_arr[i];build_heap_min(adjusted_array,k);for(int j=k;j<length;j++){if(adjusted_array[1]<p_arr[j]){adjusted_array[1]=p_arr[j];min_heapify_recur(adjusted_array,1,k);}}for(int m=1;m<=k;m++)p_res[m-1]=adjusted_array[m]; delete [] adjusted_array;//拷贝给p_res后再删除adjusted_arrayreturn;}
这是main.cpp
//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<length;i++) //为了方便,这里认为数组下标从0开始计数。printf("\t%d",p_arr[i]);printf("\n");}int main(){//top Kint top_k_number = 6;int * p_res = new int[top_k_number];int heap_size2 = sizeof(src_arr_top_k)/sizeof(int); printf("Top k is :%d\n",top_k_number); printf("Before top k:\n");print_arr_2(src_arr_top_k,top_k_number);top_k(src_arr_top_k, heap_size2,top_k_number, p_res );printf("After top k:\n");print_arr_2(p_res,top_k_number);delete [] p_res;int a = getchar();return 0;}输出结果如下
- 排序算法整理(6)堆排序的应用,top K 问题
- 堆排序在TOP K问题中的应用
- 堆排序及top K 算法
- 大小堆排序 & Top K 问题
- 堆排序解决 top k 问题
- 堆排序(TOP K)
- Java 堆排序 Top K
- 堆的应用之TOP K问题
- Top K问题——基于堆排序
- TOP-K问题-堆排序和快排实现
- 大堆排序,TOP K 问题
- 堆排序算法二(堆排序算法的应用)
- 排序算法整理之堆排序
- 排序算法整理(5)堆排序
- 算法整理-排序(堆排序)
- 微信红包问题求前K个元素(即堆排序的应用)
- 其他排序算法:快速、归并、堆排序(top N问题)
- hadoop 中文词频排序 top-k 问题
- JavaSwing图形界面编程之JApplet(六)
- 正则表达式 - 双引号内字符转星号/单词首字母转大写
- java学习脚印 : 错误列表 Errorlist
- memmove和memcpy
- 位、字节(字符)、K、M、G关系及转换
- 排序算法整理(6)堆排序的应用,top K 问题
- windows下系统进程system占用80端口
- HDU 3681 Prison Break (搜索+状压dp)
- 黑马程序员_<<字节流(含子类)和字节缓冲流(InputStream,OutputStream,BufferedInputStream,BufferedOutputStream)>>
- MFC文件夹打开的操作
- Cocos2dx中Android部分的c++和java实现相互调用
- 黑马程序员————————C#基础知识(三)
- 使用vb.net 语言将sqlserver数据库中的数据显示到bomboBox中的代码
- 二极管与、或门,三极管非门电路原理