Top K by Quickselect finds the largest elements by partitioning the array so that the top elements occupy one side. It uses the same idea as Quickselect, but returns a set instead of a single element.
This method is faster than heap-based approaches when the data is in memory and only a single pass with partitioning is needed.
Problem
Given an array of length and an integer , return the largest elements of .
The output does not need to be sorted unless required.
Algorithm
Find the -th smallest element using Quickselect, then take all elements greater than or equal to it.
top_k_by_quickselect(A, k):
n = length(A)
target = n - k
nth_element(A, target)
return A[target..n-1]If sorted output is required, sort the resulting segment.
Example
Let
and
We compute:
After partition:
Take:
These are the top 3 elements.
Correctness
After applying Nth Element at index , all elements to the right are greater than or equal to . Therefore they represent the largest elements.
The partition property ensures correctness without full sorting.
Complexity
| case | time |
|---|---|
| average | |
| worst |
With randomized pivot or introselect fallback:
Sorting the final elements adds:
Space:
When to Use
Use this method when:
- data fits in memory
- you want optimal average performance
- ordering of the top is not required or can be added later
For streaming data or strict memory bounds, heap-based methods are more appropriate.
Implementation
import random
def top_k_by_quickselect(a, k):
def partition(left, right, pivot_index):
pivot = a[pivot_index]
a[pivot_index], a[right] = a[right], a[pivot_index]
store = left
for i in range(left, right):
if a[i] < pivot:
a[store], a[i] = a[i], a[store]
store += 1
a[right], a[store] = a[store], a[right]
return store
def nth_element(left, right, k):
while True:
if left == right:
return
pivot_index = random.randint(left, right)
pivot_index = partition(left, right, pivot_index)
if pivot_index == k:
return
elif k < pivot_index:
right = pivot_index - 1
else:
left = pivot_index + 1
n = len(a)
target = n - k
nth_element(0, n - 1, target)
return a[target:]import "math/rand"
func TopKByQuickselect(a []int, k int) []int {
var partition func([]int, int, int, int) int
partition = func(a []int, left, right, pivotIndex int) int {
pivot := a[pivotIndex]
a[pivotIndex], a[right] = a[right], a[pivotIndex]
store := left
for i := left; i < right; i++ {
if a[i] < pivot {
a[store], a[i] = a[i], a[store]
store++
}
}
a[right], a[store] = a[store], a[right]
return store
}
var nthElement func(int, int, int)
nthElement = func(left, right, k int) {
for {
if left == right {
return
}
pivotIndex := left + rand.Intn(right-left+1)
pivotIndex = partition(a, left, right, pivotIndex)
if pivotIndex == k {
return
} else if k < pivotIndex {
right = pivotIndex - 1
} else {
left = pivotIndex + 1
}
}
}
n := len(a)
target := n - k
nthElement(0, n-1, target)
return a[target:]
}