這是一個經典的算法題,下面給出的算法都在給定的數組基礎上進行,好處時不用分配新的空間,壞處是會破壞原有的數組,可以自己分配新的空間以避免對原有數組的破壞。
思路一
先直接排序,再取排序后數據的前k個數。
排序算法用最快的堆排序,復雜度也會達到O(N*logN).
void filterDown(int* disorder, int pos, int size){ int temppos=pos,temp=0; while(temppos<size/2){ if(2*temppos+2<size){ if(disorder[2*temppos+1]>disorder[2*temppos+2]){ if(disorder[temppos]<disorder[2*temppos+1]){ temp=disorder[temppos]; disorder[temppos]=disorder[2*temppos+1]; disorder[2*temppos+1]=temp; temppos=2*temppos+1; } else{ break; } } else{ if(disorder[temppos]<disorder[2*temppos+2]){ temp=disorder[temppos]; disorder[temppos]=disorder[2*temppos+2]; disorder[2*temppos+2]=temp; temppos=2*temppos+2; } else{ break; } } } else if(disorder[temppos]<disorder[2*temppos+1]){ temp=disorder[temppos]; disorder[temppos]=disorder[2*temppos+1]; disorder[2*temppos+1]=temp; temppos=2*temppos+1; } else{ break; } } } void heapSort(int* disorder, int size){ int bottomRowSize=2; while(bottomRowSize<size){ bottomRowSize*=2; } int temp=0,i=0; for(int j=size/2-1;j>=0;j--){ filterDown(disorder, j, size); } for(int j=size-1;j>0;j--){ temp=disorder[0]; disorder[0]=disorder[j]; disorder[j]=temp; filterDown(disorder,0,j); } } int _tmain(int argc, _TCHAR* argv[]) { const int size=200; const int maxnum = 10000; const int k=10; int* disorder=new int[size]; srand((unsigned) time(NULL)); for(int i=0;i<size;i++){ disorder[i]=rand()%maxnum; } heapSort(disorder,size); for(int i=0;i<k;i++){ cout<<disorder[i]<<endl; } return 0; }
當k接近於N時,可以用這種算法。
思路二
先排序前k個數,對於后面N-k個數,依次進行插入。
時間復雜度為O(k*n)
void insertSort(int* disorder, int size){ int temp=0,i=0; for(int j=1;j<size;j++){ temp=disorder[j]; for(i=j;i>0;i--){ if(temp<disorder[i-1]){ disorder[i] = disorder[i-1]; } else{ break; } } disorder[i]=temp; } } int _tmain(int argc, _TCHAR* argv[]) { const int size=200; const int maxnum = 10000; const int k=10; int* disorder=new int[size]; srand((unsigned) time(NULL)); int i=0,temp; for(;i<size;i++){ disorder[i]=rand()%maxnum; } insertSort(disorder,k); for(int j=k;j<size;j++){ temp=disorder[j]; for(i=k-1;i>=0;i--){ if(temp<disorder[i]){ disorder[i+1] = disorder[i]; } else{ break; } } disorder[i+1]=temp; } for(int i=0;i<k;i++){ cout<<disorder[i]<<endl; } return 0; }
當k很小時,可以用這種算法
思路三
對前k個數,建立最大堆,對於后面N-k個數,依次和最大堆的最大數比較,如果小於最大數,則替換最大數,並重新建立最大堆。
時間復雜度為O(N*logk)
void filterDown(int* disorder, int pos, int size){ int temppos=pos,temp=0; while(temppos<size/2){ if(2*temppos+2<size){ if(disorder[2*temppos+1]>disorder[2*temppos+2]){ if(disorder[temppos]<disorder[2*temppos+1]){ temp=disorder[temppos]; disorder[temppos]=disorder[2*temppos+1]; disorder[2*temppos+1]=temp; temppos=2*temppos+1; } else{ break; } } else{ if(disorder[temppos]<disorder[2*temppos+2]){ temp=disorder[temppos]; disorder[temppos]=disorder[2*temppos+2]; disorder[2*temppos+2]=temp; temppos=2*temppos+2; } else{ break; } } } else if(disorder[temppos]<disorder[2*temppos+1]){ temp=disorder[temppos]; disorder[temppos]=disorder[2*temppos+1]; disorder[2*temppos+1]=temp; temppos=2*temppos+1; } else{ break; } } } int _tmain(int argc, _TCHAR* argv[]) { const int size=200; const int maxnum = 10000; const int k=10; int* disorder=new int[size]; srand((unsigned) time(NULL)); int i=0,temp; for(;i<size;i++){ disorder[i]=rand()%maxnum; } for(int j=k/2-1;j>=0;j--){ filterDown(disorder, j, k); } for(int j=k;j<size;j++){ if(disorder[j]<disorder[0]){ disorder[0]=disorder[j]; filterDown(disorder,0,k); } } for(int j=k-1;j>0;j--){ temp=disorder[0]; disorder[0]=disorder[j]; disorder[j]=temp; filterDown(disorder,0,j); } for(int i=0;i<k;i++){ cout<<disorder[i]<<endl; } return 0; }
當k和N都很大時,這種算法比前兩種算法要快很多。
