(1)思路
类似于快速排序,此处选择第一个元素作为枢轴flag, 调整之后flag左边的都比flag小,右边的都比flag大,此时比较flag的下标index和要查找的k,如果k==index,那么就找到了;如果index>k,说明k在flag的左边区间中;如果index>k,说明k在flag的右边区间中
(2)代码
private void quick_select(int[] a, int begin, int end,int k)
{
if(begin==end && end==k) //必须要加上此判断,因为可能出现区间中只有一个值,该值就是所求的情况
System.out.println(a[end]);
if(begin<end)
{
int index = adjustNewx(a,begin,end);
if(index==k)
System.out.println(a[index]);
else if(index>k) //说明在flag的左边区间中
quick_select(a, 0, index-1, k);
else //在flag的右边区间中
quick_select(a, index+1, a.length-1, k);
}
}
private int adjustNewx(int[] a, int begin, int end)
{
int flag = a[begin];
while(begin<end)
{
while(a[end]>=flag && begin<end)
end--;
if(begin<end)
a[begin] = a[end];
while(a[begin]<=flag && begin<end)
begin++;
if(begin<end)
a[end] = a[begin];
}
a[begin] = flag;
return begin;
}
(3)注意
1.当k在flag的右边区间时,仍然传入k,而不是k-index-1,因为我们这里使用的是下标来判断,如果传入k-index-1,那么就不可能出现k==index的情况了
2.一般的快排只用判断begin<end的情况,但是此处需要处理区间只有一个元素的情况,所以必须要加上begin==end的判断
(4)测试
@Test
public void getK()
{
int[] a = {16, 105, 3, 31, 61, 50, 61, 80, 78, 4};
for(int k=0; k<a.length; k++)
quick_select(a,0,a.length-1,k);
}
结果为:
3
4
16
31
50
61
61
78
80
105