显然,最直接的方法就是用排序算法对数组先进行从小到大的排序,然后直接提取L[k],便得到了第K小元素,但其平均时间复杂度将达到O(nlogn)以上。此外,还可以采用小顶堆的方法,每次堆定元素都是最小元素,时间复杂度为O(n+logn)。
下面,介绍一个比较好的算法,它是基于快速排序的划分操作的。
主要思想为:
从数组L[1.....n]中选择Pivot(随机地或者直接取第一个)进行和快速排序一样的划分操作,表L[1.....n]被划分为L[1.....m-1]和L[m+1......n],其中L(m)=pivot;
讨论m和k的大小关系:
1)当m=k时,显然pivot就是所要寻找的元素,直接返回pivot就好。
2)当m<k时,则所要寻找的元素一定落在L[m+1.....n]中,从而可以对L[m+1.....n]递归地查找第m-k小元素。
3)当m>k时,则所要寻找的元素一定落在L[1......m+1]中,从而可以对L[1......m+1]递归地查找第K小元素。
这个算法的时间复杂度在平均的情况下可以达到O(n).
具体实现如下:
1 int kth_elem(int a[],int low,int high,int k) 2 { 3 int pivot=a[low]; 4 int low_temp=low; 5 int high_temp=high; 6 while(low<high){ 7 while(low<high&&a[high]>=pivot){ 8 --high; 9 } 10 a[low]=a[high]; 11 while(low<high&&a[low]<=pivot){ 12 ++low; 13 } 14 a[high]=a[low]; 15 } 16 a[low]=pivot; 17 18 //上面为快速排序中的划分算法 19 // 下面为本算法中所述内容 20 if(low==k){ 21 return a[low]; 22 } 23 else if(low>k){//在前一部分中递归查找 24 return kth_elem(a,low_temp,low-1,k); 25 } 26 else{//在后一部分递归查找 27 return kth_elem(a,low+1,high_temp,m-k); 28 } 29 30 }