Rearrange an array so that the element at position k is the same as in sorted order, with partition guarantees.
Nth Element rearranges an array so that the element at index is exactly the element that would appear at that position in a fully sorted array.
All elements before index are less than or equal to it, and all elements after are greater than or equal to it. The order within those partitions is not sorted.
This is a partition based selection primitive widely used in standard libraries.
Problem
Given an array and an index , reorder the array such that:
- is the k-th smallest element
- for all ,
- for all ,
Algorithm
Use a Quickselect style partition process until the pivot lands at index .
nth_element(A, k):
left = 0
right = length(A) - 1
while true:
pivot_index = choose_pivot(A, left, right)
pivot_index = partition(A, left, right, pivot_index)
if pivot_index == k:
return
else if k < pivot_index:
right = pivot_index - 1
else:
left = pivot_index + 1Key Property
After execution:
The array is only partially ordered.
Example
Let
and
After applying Nth Element, one valid result is:
The element at index is , which matches the sorted position. The left and right sides are partitioned but not sorted internally.
Correctness
Each partition step places the pivot in its final sorted position. By restricting the search interval to the side containing index , the algorithm ensures that eventually the pivot lands exactly at .
The partition invariant guarantees correct ordering relative to the pivot.
Complexity
| case | time |
|---|---|
| average | |
| worst |
With randomized pivot or introselect fallback:
Space:
When to Use
Use Nth Element when:
- you need partitioning around a rank
- you want top-k elements without sorting
- you plan to sort only a prefix or suffix
It is the standard primitive behind efficient partial sorting.
Implementation
import random
def nth_element(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
left, right = 0, len(a) - 1
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 + 1import "math/rand"
func NthElement(a []int, k int) {
left, right := 0, len(a)-1
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
}
}
}