Top-K選擇
-
說明
random文件裏面含有一系列正整數。要求選擇其中最大的k(k=10)個數,並顯示。 -
目的
考察top-K選擇算法的效率,本次將k設置爲10。 -
程序流程
1、讀文件到內存數組A;
2、記錄程序開始時間;
3、循環1百次
4、 執行top-K選擇算法;
(要求不能改變數組A中的內容,對數組A只能讀,不能寫)
5、循環1百次結束
6、記錄程序結束時間;
7、顯示1百萬次循環的執行時間;
8、顯示選擇的top-K個數。
9、程序編完之後,理論上分析一下算法的時間複雜性。
解決方法
(解決方法的實現代碼可能還存在着問題,但思路是正確的。)
-
第一種
對n個數由大到小排序,然後選擇前k個最大的數。 -
排序算法有很多種,快速排序應該綜合看來是最優,本代碼使用最簡單但也是最慢的排序算法來解決,時間複雜度爲o(k*n^2)。
-
c語言實現如下
#include<stdio.h>
#include<time.h>
int Read();
int i=0,a[100000];
int main(){
clock_t start,end;
start=clock();
float runtime;
int j=0,k=0;
Read();
for(int n=0;n<10000;n++){
while(a[j]){
k=j;
while(a[k]){
if(a[j]<=a[k]){
int x=0;
x=a[j];
a[j]=a[k];
a[k]=x;
}
k++;
}
k=0;
j++;
}
printf("第%d次Top-10=",n+1);
for(j=0;j<10;j++){
printf("%d ",a[j]);
}
printf("\n");
j=0;
}
end=clock();
runtime=(double)(end-start);
printf("程序運行時間爲%f毫秒(ms)\n",runtime);
return 0;
}
int Read(){
FILE *data;
data=fopen("random.txt","r");
while(fscanf(data,"%d",&a[i])!=EOF){
i++;
}
fclose(data);
}
-
第二種
(1)掃描數組A, 選擇最大的數,並做標記;
(2) 掃描數組A, 選擇第二大的數,並做標記;
……
(k) 掃描數組A, 選擇第K大的數,並做標記; -
代碼仍存在問題未能解決,在於每次將數組中的最大值置1後,無法恢復,如果每次使用Read()函數重讀只能運行十次,整體來看時間複雜度爲o(kn)。
-
c語言實現如下
#include<stdio.h>
#include<time.h>
#include<string.h>
int Read();
int i=0,a[100000];
int main(){
clock_t start,end;
start=clock();
float runtime;
int j=0,num=0,max=0,k=0,b[10]={0};
Read();
for(int n=0;n<10;n++){
for(j=0;j<10;j++){
max=0,k=0;
while(a[k]){
if(a[k]>max){
max=a[k];
num=k;
}
k++;
}
b[j]=max;
a[num]=1;
}
printf("第%d次Top-10=",n+1);
for(j=0;j<10;j++){
printf("%d ",b[j]);
}
printf("\n");
}
end=clock();
runtime=(double)(end-start);
printf("程序運行時間爲%f毫秒(ms)\n",runtime);
return 0;
}
int Read(){
FILE *data;
data=fopen("random.txt","r");
while(fscanf(data,"%d",&a[i])!=EOF){
i++;
}
fclose(data);
}
-
第三種
把數組的前k個數先放入優先級隊列(底層實現是小根堆,STL模板庫有現成的庫函數), 從第k+1個數開始掃描。
(1) 如果當前數比優先級隊列的隊列頭(小根堆的堆頂)大,說明當前數需要放入優先級隊列,這時先彈出優先級隊列的隊列頭,然後將當前數插入優先級隊列。
(2) 如果當前數比優先級隊列的隊列頭(小根堆的堆頂)小,說明當前數不會是top-k中的數,直接濾過,處理下一個數。 -
在放入優先級隊列比較時,小根堆是最優的比較方法,時間複雜度僅爲堆的高度h=log(2)k(即以2爲底k的對數),總體時間複雜度再乘以外界的n,即o(n*log(2)k)。
本代碼使用隊列內逐個比較方法,所以時間複雜度爲o(kn)。 -
c語言實現如下
#include<stdio.h>
#include<time.h>
#include<string.h>
int Read();
int i=0,a[1000000];
int main(){
clock_t start,end;
start=clock();
float runtime;
int h[10]={0};
int k=0,x=0,j=0;
Read();
for(int n=0;n<1000000;n++){
j=0;
while(a[j]){
if(a[j]>h[0]){
h[0]=a[j];
for(k=0;k<9;k++){
if(h[k]>h[k+1]){
x=h[k];
h[k]=h[k+1];
h[k+1]=x;
}
}
}
j++;
}
printf("第%d次Top-10=",n+1);
for(k=9;k>=0;k--){
printf("%d ",h[k]);
h[k]=0;
}
printf("\n");
}
end=clock();
runtime=(double)(end-start);
printf("程序運行時間爲%f毫秒(ms)\n",runtime);
return 0;
}
int Read(){
FILE *data;
data=fopen("random.txt","r");
while(fscanf(data,"%d",&a[i])!=EOF){
i++;
}
fclose(data);
}
備註
- 打印數據需要花費很長時間,如果只打算比較各算法的運行時間,可以將打印的部分註釋掉。
- 計算運行時間需要調用time.h,並有計算時長代碼如下
#include<time.h>
clock_t start,end;
start=clock();
float runtime;
end=clock();
runtime=(double)(end-start);
printf("程序運行時間爲%f毫秒(ms)\n",runtime);
- 打開一個文件,並讀取其中數據的函數實現如下
int i=0,a[1000000];
int Read(){
FILE *data;
data=fopen("random.txt","r");
while(fscanf(data,"%d",&a[i])!=EOF){
i++;
}
fclose(data);
}
- random.txt文件中包含的是諸如下列形式的許多整數,整數大小與數量無要求,可以自行生成。
12960
560
28628
9692
2842
30927