1、算法思想
问题描述:从数组array中找出第i小的元素(要求array中没有重复元素的情况),这是个经典的“线性时间选择(Selection in expected linear time)”问题。
思路:算法导论215页9.2 Selection in expect linear time
2、java实现
思路:算法导论216页伪代码
/*期望为线性时间的选择算法,输入要求,array中没有重复的元素*/
public static int randomizedSelect(int[] array,int start,int end,int i) {
if (start==end) {
return array[start];
}
int middle=randomizedPartition(array, start, end);
int k=middle-start+1;
if (i==k) {
return array[middle];
}else if (i<k) {
return randomizedSelect(array, start, middle-1, i);
}else {
return randomizedSelect(array, middle+1, end, i-k);
}
}
randomizedPartition(array,start,end)参见:
【算法导论-010】快速排序(quickSort)
3、非递归版本
/*非递归版本的线性时间选择*/
public static int iterativeRandomizedSelect(int[] array,int start,int end,int i) {
int result=0;
while (start<=end) {
if (start==end) {
return array[start];
}
int middle=randomizedPartition(array, start, end);
int k=middle-start+1;
if (i==k) {
result= array[i];
} else if (i<k) {
end=middle-1;
}else {
start=middle+1;
i=i-k;
}
}
return result;
}
*****************************************************************************************************************
扩展一道课后题:《算法导论》P223 9.3-7
Describe an O(n) algorithm that, given a set S of n distinct numbers and a positive integer k n, determines the k numbers in S that are closest to the median of S.
翻译过来即:在集合S中选出最接近中位数的k个元素。
思路:线性选择出第n/2小的元素就是中位数middle,第(n-k)/2的元素low,第(n+k)/2小的元素high,然后遍历整个数组——大于low且小于high且不等于middle的元素就是离middle最近的k个元素。
public static LinkedList<Integer> getClosetToMedian(int[] array,int k) {
LinkedList<Integer> linkedList=new LinkedList<Integer>();
int n=array.length;
int median=randomizedSelect(array, 0, n-1, n/2);
int low=randomizedSelect(array, 0, n-1, (n-k)/2);
int high=randomizedSelect(array, 0, n-1, (n+k)/2);
for (int i : array) {
if (i>=low&&i<=high&&i!=median) {
linkedList.add(i);
}
}
return linkedList;
}