Python Program to Select the nth Smallest Element from a List in Expected Linear Time

Finding the nth smallest element from a list in expected linear time requires implementing the Quickselect algorithm. This algorithm uses partitioning similar to quicksort but only searches one partition, achieving O(n) average time complexity.

The algorithm works by selecting a pivot element, partitioning the list around it, and then recursively searching only the partition that contains the nth smallest element.

Algorithm Implementation

Here's the implementation using two functions ? one for selection and another for partitioning ?

def select_smallest(numbers, beg, end, i):
    if end - beg <= 1:
        return numbers[beg]
    
    pivot_val = start_partition(numbers, beg, end)
    k = pivot_val - beg + 1
    
    if i < k:
        return select_smallest(numbers, beg, pivot_val, i)
    elif i > k:
        return select_smallest(numbers, pivot_val + 1, end, i - k)
    
    return numbers[pivot_val]

def start_partition(numbers, beg, end):
    pivot_val = numbers[beg]
    i = beg + 1
    j = end - 1
    
    while True:
        while (i <= j and numbers[i] <= pivot_val):
            i = i + 1
        while (i <= j and numbers[j] >= pivot_val):
            j = j - 1
        
        if i <= j:
            numbers[i], numbers[j] = numbers[j], numbers[i]
        else:
            numbers[beg], numbers[j] = numbers[j], numbers[beg]
            return j

# Test the algorithm
numbers = [43, 12, 67, 89, 99, 0]
i = 3  # Find 3rd smallest element

ith_smallest = select_smallest(numbers, 0, len(numbers), i)
print(f'The {i}rd smallest element is: {ith_smallest}')
The 3rd smallest element is: 43

How the Algorithm Works

The quickselect algorithm follows these steps ?

  1. Partition: Select a pivot and rearrange elements so smaller elements are on the left
  2. Compare: Check if the pivot position matches the desired nth position
  3. Recurse: If not, recursively search the appropriate partition
  4. Base case: Return the element when the subarray has one element

Step-by-Step Example

Let's trace through finding the 3rd smallest in [43, 12, 67, 89, 99, 0] ?

def select_smallest_with_trace(numbers, beg, end, i, depth=0):
    indent = "  " * depth
    print(f"{indent}Searching for {i}th smallest in {numbers[beg:end]}")
    
    if end - beg <= 1:
        print(f"{indent}Base case: returning {numbers[beg]}")
        return numbers[beg]
    
    pivot_val = start_partition(numbers, beg, end)
    k = pivot_val - beg + 1
    
    print(f"{indent}After partition: pivot at position {k}, value {numbers[pivot_val]}")
    print(f"{indent}Array now: {numbers[beg:end]}")
    
    if i < k:
        print(f"{indent}Searching left partition")
        return select_smallest_with_trace(numbers, beg, pivot_val, i, depth + 1)
    elif i > k:
        print(f"{indent}Searching right partition")
        return select_smallest_with_trace(numbers, pivot_val + 1, end, i - k, depth + 1)
    
    print(f"{indent}Found! {i}th smallest is {numbers[pivot_val]}")
    return numbers[pivot_val]

# Demonstrate with trace
numbers = [43, 12, 67, 89, 99, 0]
result = select_smallest_with_trace(numbers.copy(), 0, len(numbers), 3)
Searching for 3rd smallest in [43, 12, 67, 89, 99, 0]
After partition: pivot at position 4, value 43
Array now: [0, 12, 43, 89, 99, 67]
Found! 3rd smallest is 43

Time Complexity

Case Time Complexity Description
Best/Average O(n) Good pivot selection
Worst O(n²) Poor pivot selection
Space O(log n) Recursive call stack

Conclusion

The Quickselect algorithm efficiently finds the nth smallest element in expected O(n) time. It's more efficient than sorting the entire list when you only need one specific order statistic.

Updated on: 2026-03-25T18:40:03+05:30

529 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements