Common Algorithms
Selection Sort
When memory writes are expensive, such as writing to flash storage or slow external devices, minimizing the number of swap operations becomes important. Selection sort addresses this by guaranteeing exactly n-1 swaps regardless of input, making it useful when write operations are costly.
Comparison with Bubble Sort
basic.py
# Basic selection sort
def selection_sort(arr):
"""Selection sort implementation"""
n = len(arr)
# Selection sort implementation
for i in range(n - 1):
# Find minimum in unsorted portion
min_index = i
for j in range(i + 1, n):
if arr[j] < arr[min_index]:
min_index = j
# Swap minimum with first unsorted element
arr[i], arr[min_index] = arr[min_index], arr[i]
# Test selection sort
numbers =
print("Before:", numbers)
selection_sort(numbers)
print("After: ", numbers)
# Basic selection sort
def selection_sort(arr):
"""Selection sort implementation"""
n = len(arr)
# Selection sort implementation
for i in range(n - 1):
# Find minimum in unsorted portion
min_index = i
for j in range(i + 1, n):
if arr[j] < arr[min_index]:
min_index = j
# Swap minimum with first unsorted element
arr[i], arr[min_index] = arr[min_index], arr[i]
# Test selection sort
numbers =
print("Before:", numbers)
selection_sort(numbers)
print("After: ", numbers)
# Basic selection sort
def selection_sort(arr):
"""Selection sort implementation"""
n = len(arr)
# Selection sort implementation
for i in range(n - 1):
# Find minimum in unsorted portion
min_index = i
for j in range(i + 1, n):
if arr[j] < arr[min_index]:
min_index = j
# Swap minimum with first unsorted element
arr[i], arr[min_index] = arr[min_index], arr[i]
# Test selection sort
numbers =
print("Before:", numbers)
selection_sort(numbers)
print("After: ", numbers)
trace.py
# Selection sort with trace
def selection_sort_trace(arr):
"""Selection sort with step-by-step trace"""
n = len(arr)
# Trace each pass
for i in range(n - 1):
print(f"Pass {i + 1}:")
# Find minimum
min_index = i
for j in range(i + 1, n):
if arr[j] < arr[min_index]:
min_index = j
print(f" Min in unsorted portion: {arr[min_index]} at index {min_index}")
# Swap
if min_index != i:
print(f" Swap positions {i} and {min_index}")
arr[i], arr[min_index] = arr[min_index], arr[i]
else:
print(" Already in position")
print(f" Result: {arr}")
# Test with trace
numbers = [5, 2, 8, 1, 9]
print("Initial:", numbers)
print()
selection_sort_trace(numbers)
find_max.py
# Find maximum variant
def selection_sort_max(arr):
"""Selection sort finding maximum"""
n = len(arr)
# Selection sort finding maximum
for i in range(n - 1, 0, -1):
# Find maximum in unsorted portion
max_index = 0
for j in range(1, i + 1):
if arr[j] > arr[max_index]:
max_index = j
# Swap maximum with last unsorted element
arr[i], arr[max_index] = arr[max_index], arr[i]
# Test maximum variant
numbers = [64, 25, 12, 22, 11]
print("Before:", numbers)
selection_sort_max(numbers)
print("After: ", numbers)
count.py
# Count comparisons and swaps
def selection_sort_counted(arr):
"""Selection sort that counts operations"""
n = len(arr)
comparisons = 0
swaps = 0
# Count operations
for i in range(n - 1):
min_index = i
for j in range(i + 1, n):
comparisons += 1
if arr[j] < arr[min_index]:
min_index = j
if min_index != i:
swaps += 1
arr[i], arr[min_index] = arr[min_index], arr[i]
return comparisons, swaps
# Test on different inputs
sorted_list = [1, 2, 3, 4, 5]
reversed_list = [5, 4, 3, 2, 1]
random_list = [3, 1, 4, 2, 5]
comp1, swap1 = selection_sort_counted(sorted_list.copy())
print(f"Already sorted: {comp1} comparisons, {swap1} swaps")
comp2, swap2 = selection_sort_counted(reversed_list.copy())
print(f"Reverse sorted: {comp2} comparisons, {swap2} swaps")
comp3, swap3 = selection_sort_counted(random_list.copy())
print(f"Random order: {comp3} comparisons, {swap3} swaps")
compare.py
# Compare with bubble sort
def bubble_sort_swaps(arr):
"""Bubble sort counting swaps"""
n = len(arr)
swaps = 0
for i in range(n - 1):
for j in range(n - i - 1):
if arr[j] > arr[j + 1]:
swaps += 1
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return swaps
def selection_sort_swaps(arr):
"""Selection sort counting swaps"""
n = len(arr)
swaps = 0
for i in range(n - 1):
min_index = i
for j in range(i + 1, n):
if arr[j] < arr[min_index]:
min_index = j
if min_index != i:
swaps += 1
arr[i], arr[min_index] = arr[min_index], arr[i]
return swaps
# Compare swap counts
reversed_list = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
bubble_swaps = bubble_sort_swaps(reversed_list.copy())
print(f"Bubble sort swaps: {bubble_swaps}")
selection_swaps = selection_sort_swaps(reversed_list.copy())
print(f"Selection sort swaps: {selection_swaps}")
print("\nSelection sort makes fewer swaps!")
Characteristics
- Time complexity: O(n^2) - two nested loops
- Space complexity: O(1) - sorts in place
- Unstable: equal elements may change relative order
- Best case: O(n^2) - always scans entire unsorted portion
- Worst case: O(n^2) - same as best case
- Fewer swaps: only n-1 swaps
find_minimum
Scan unsorted portion to locate the smallest element
minimal_swaps
Selection sort performs exactly n-1 swaps, regardless of input order
Exercise: practical.py
Implement selection sort to arrange a playlist by song duration, tracking and displaying the number of swaps performed