设计一个平均时间为O(n)的算法,在n(1<=n<=1000)个无序的整数中找出第k小的数。
提示:函数int partition(int a[],int left,int right)的功能是根据a[left]~a[right]中的某个元素x(如a[left])对a[left]~a[right]进行划分,划分后的x所在位置的左段全小于等于x,右段全大于等于x,同时利用x所在的位置还可以计算出x是这批数据按升非降序排列的第几个数。因此可以编制int find(int a[],int left,int right,int k)函数,通过调用partition函数获得划分点,判断划分点是否第k小,若不是,递归调用find函数继续在左段或右段查找。
这里利用快速排序的思路,快排就是找个基准元素,一般是左边第一个,然后从右边开始比较,当右边的元素大于等于基准元素时,就继续(right--) 当小于时就跳出这个循环,然后将这个元素填入基准元素所处的位置,然后从左边开始比较,当左边的元素小于等于基准元素时(left++)直到左边的元素大于基准元素,就将左边的这个元素填入之前右边空出来那个位置,循环直到左右的下标相等即left==right 然后就将基准元素填入这个位置 至此第一次快排结束,基准左边都是小于等于他的,基准右边都是大于等于他的
#include <iostream>
using namespace std;
int partition(int a[],int left,int right){
int w = a[left];
while(left<right){
//先从右边开始 当右边大于等于基数就跳过
while(left<right&&a[right]>=w){
right--;
}
//当右边小于基数就跳出循环 然后让右边的数来到基数位置
a[left] = a[right];
//然后就从左边继续 左边小于等于基数就跳过
while(left<right&&a[left]<=w){
left++;
}
//左边大于基数时 此时右边哪个来到基数的位置是空的 让左边的数座落到那个位置
a[right] = a[left];
}
//此时左右指针相遇 把基数填入
a[left] = w;
return left;
}
int find(int a[],int left,int right,int k){
int position = partition(a,left,right);
//如果索要查找的第k个元素(崽数组中下标为k-1)刚好就是这个快排的基准元素排序后的下标就直接输出
if(k-1 == position){
cout<<a[k-1]<<endl;
}
else if(k-1<position){ //索要查找的第k个小的元素的位置小于position位置 那么就是position位置之前的某个数
//因为快排之后 position位置之前的元素都小于position位置的元素
find(a,left,position-1,k);
}
else{
find(a,position+1,right,k);
}
return 0;
}
int main(){
int n,k;
cin>>n>>k;
int a[1000];
for(int i = 0;i<n;i++){
cin>>a[i];
}
find(a,0,n-1,k);
return 0;
}