Selection and insertion sort

Build a sorted prefix. Count comparisons.

Selection sort repeatedly pulls the smallest remaining item into place. Insertion sort grows a sorted prefix by inserting the next item. Both are about comparisons.

Goal

Sort a price list both ways and print the comparisons.

Selection sort

def selection_sort(items):
    xs = list(items)
    steps = 0
    n = len(xs)
    for i in range(n):
        lo = i
        for j in range(i + 1, n):
            steps += 1
            if xs[j] < xs[lo]:
                lo = j
        xs[i], xs[lo] = xs[lo], xs[i]
    return xs, steps

print(selection_sort([31, 10.5, 22.0, 10.5]))

Insertion sort

def insertion_sort(items):
    xs = list(items)
    steps = 0
    for i in range(1, len(xs)):
        key = xs[i]
        j = i - 1
        while j >= 0:
            steps += 1
            if xs[j] > key:
                xs[j + 1] = xs[j]
                j -= 1
            else:
                break
        xs[j + 1] = key
    return xs, steps

print(insertion_sort([31, 10.5, 22.0, 10.5]))

Insertion sort does fewer comparisons when the list is almost sorted. Selection sort always scans the suffix.

From a file

Download unsorted.txt, Add files, then:

from pathlib import Path

def selection_sort(items):
    xs = list(items)
    n = len(xs)
    for i in range(n):
        lo = i
        for j in range(i + 1, n):
            if xs[j] < xs[lo]:
                lo = j
        xs[i], xs[lo] = xs[lo], xs[i]
    return xs

nums = [float(line) for line in Path("unsorted.txt").read_text(encoding="utf-8").splitlines() if line.strip()]
print(nums)
print(selection_sort(nums))
Tip

sorted(xs) is the right tool in production. You are implementing the idea so the nested loops are visible.