问题
I know that I can get the Kth order statistic (i.e. the kth smallest number in an array) by using quickselect in almost linear time, but what if I needed the k smallest elements of an array?
The wikipedia link has a pseudocode for the single-element lookup, but not for the k smallest elements lookup.
How should quickselect be modified to attain it in linear time (if possible) ?
回答1:
Actually modifying quickselect is not needed. If I had an array (called arrayToSearch in this example) and I wanted the k smallest items I'd do this:
int i;
int k = 10; // if you wanted the 10 smallest elements
int smallestItems = new Array(k);
for (i = 0; i < k; i++)
{
smallestItems[i] = quickselect(i, arrayToSearch);
}
Edit: I was under the assumption that k would be a relatively small number which would make the effective Big-O O(n). If not assuming k is small this would have a speed of O(k*n), not linear time. My answer is easier to comprehend, and applicable for most practical purposes. recursion.ninja's answer may be more technically correct, and therefore better for academic purposes.
回答2:
I believe that after you use quickselest to find the k
-th statictic, you will automatically find that the first k
elements of the resulting array are the k
smallest elements, only probably not sorted.
Moreover, quickselect actually does partitioning with respect to the k
-th statistics: all the elements before k
-th statistic is smaller (or equal) to it, and all the elements after are bigger or equal. This is easy to prove.
Note, for example that for C++ nth_element
The other elements are left without any specific order, except that none of the elements preceding nth are greater than it, and none of the elements following it are less.
If you need not just k
smallest elements, but sorted k
smallest elements, you can of course sort them after quickselect.
来源:https://stackoverflow.com/questions/31270450/adapting-quickselect-for-smallest-k-elements-in-an-array