寻找最小的k个数
1. 能想到的最直接的办法,就是对数组进行排序,最好的排序算法的时间复杂性为O(n*logn),这一个方法请参照各种排序算法。
2. 另外申请一个k空间数组,依次更改里面的最大值,每做一次最多要扫描一下这个K大小的空间(如果比上一次的最大值大的话,就不用扫描了,所以这里说是“最多”),整体时间复杂度为O((n-k)*k),实现代码如下:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int initData(int test[],int len); int printArray(int test[],int len); int maxOfArray(int test[],int k); int selectElement(int test[],int len,int k); int main() { const int arraySize=100; const int k=20; int test[arraySize]; initData(test,arraySize); printArray(test,arraySize); selectElement(test,arraySize,k); printArray(test,k); return 0; } int selectElement(int test[],int len,int k) { int maxIndex=maxOfArray(test,k); for(int i=k;i<len;i++) { int tmp=test[maxIndex]; if(tmp>test[i]) { test[maxIndex]=test[i]; maxIndex=maxOfArray(test,k); } } return 0; } int maxOfArray(int test[],int k) { int index=0; int tmp=test[0]; for(int i=1;i<k;i++) { if(test[i]>tmp) { index=i; tmp=test[i]; } } return index; } int initData(int test[],int len) { srand(time(NULL)); for(int i=0;i<len;i++) { test[i]=rand()%20; } return 0; } int printArray(int test[],int len) { for(int i=0;i<len;i++) { cout<<test[i]<<"\t"; } cout<<endl; return 0; }
3.第三种方式是建立一个k大小的极大堆,每一次将数据与堆头的元素比较,如果比它小,则替换之,然后更新堆的结构,除去构建堆的时间,时间复杂度为:O((n-k)*logk),代码如下:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int initData(int test[],int len); int printArray(int test[],int len); int maxHeap(int test[],int i,int k);//i为下标 int buildHeap(int test[],int arraySize,int k); int selectElement(int test[],int arraySize,int k); int main() { const int arraySize=20; const int k=5; int test[arraySize]; initData(test,arraySize); printArray(test,arraySize); buildHeap(test,arraySize,k); printArray(test,arraySize); selectElement(test,arraySize,k); printArray(test,arraySize); return 0; } int selectElement(int test[],int arraySize,int k) { for(int i=k;i<arraySize;i++) { if(test[i]<test[0]) { test[0]=test[i]; maxHeap(test,0,k); } } return 0; } int buildHeap(int test[],int arraySize,int k) { for(int i=arraySize/2-1;i>=0;i--) { maxHeap(test,i,k); } return 0; } int maxHeap(int test[],int i,int k)//i为下标 { int least=i; int left=(i+1)*2-1; int right=(i+1)*2; if(left<k&&test[left]>test[least]) least=left; if(right<k&&test[right]>test[least]) least=right; if(least!=i) { test[i]=test[i]+test[least]; test[least]=test[i]-test[least]; test[i]=test[i]-test[least]; maxHeap(test,least,k); } return 0; } int initData(int test[],int len) { srand(time(NULL)); for(int i=0;i<len;i++) { test[i]=rand()%20; } return 0; } int printArray(int test[],int len) { for(int i=0;i<len;i++) { cout<<test[i]<<"\t"; } cout<<endl; return 0; }
对堆不了解的这里插入一个3D动画http://www.benfrederickson.com/2013/10/10/heap-visualization.html
4. 第四种方法是借鉴快速排序的partition过程,partition做完后,假设返回的下标是k,那么我们确定k之前的元素都比k下标的元素要小,依次不断递归下去,时间复杂度是O(n),实现代码如下:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int partition(int test[],int p,int r); int selectElements(int test[],int p,int r,int k);//前k个最小元素; int initData(int test[],int len); int printArray(int test[],int len); int main() { const int arraySize=10; const int k=5; int test[arraySize]; initData(test,arraySize); printArray(test,arraySize); selectElements(test,0,arraySize-1,k); printArray(test,arraySize); return 0; } int selectElements(int test[],int p,int r,int k)//前k个最小元素 { if(p<=r) { int partIndex=partition(test,p,r); int len=partIndex-p+1; if(len==k) return 0; else if(len<k) { selectElements(test,partIndex+1,r,k-len); } else { selectElements(test,p,partIndex-1,k); } } return 0; } int partition(int test[],int p,int r) { int flagValue=test[r]; int k=p-1; for(int i=p;i<r;i++) { if(test[i]<flagValue) { k++; /* test[i]=test[k]+test[i];test[k]与test[i]是同一块区域的话,这样会把数据清0 test[k]=test[i]-test[k]; test[i]=test[i]-test[k]; */ int tmp=test[k]; test[k]=test[i]; test[i]=tmp; } } k++; test[r]=test[k]; test[k]=flagValue; return k; } int initData(int test[],int len) { srand(time(NULL)); for(int i=0;i<len;i++) { test[i]=rand()%20; } return 0; } int printArray(int test[],int len) { for(int i=0;i<len;i++) { cout<<test[i]<<"\t"; } cout<<endl; return 0; }