← Back to course
Python 11-12 / Week 09 / Thursday
4/6
Week 09 Β· Sorting

Thursday

Insertion sort
// Selection and insertion sort; count the work
⏱ about 30 min

Thursday: Insertion Sort

Comet sorts a hand of cards the way she always has. She picks up one card at a time and slides it into place among the cards she is already holding.

"That is not selection sort," Wren says, watching. "You never search for the smallest."

"It works, though," Comet says. "What does the evidence say about that?"

Wren laughs at his own question coming back at him. Nova projects a row of cards, with larger cards sliding right to open a gap. "How can I help?" she asks. "Count the shifts as well as the comparisons."

Comet fans her cards toward you. "Lead programmer, show us what my hands are doing."

insertion_sort()

Insertion sort takes the next item from the unsorted part. It shifts larger items of the sorted part one place right to make room. Then it drops the item into the gap.

The place is correct for now, but not always final. A smaller item that comes later can still push it right.

def insertion_sort(nums):
    for i in range(1, len(nums)):
        current = nums[i]
        j = i - 1
        while j >= 0 and nums[j] > current:
            nums[j + 1] = nums[j]
            j -= 1
        nums[j + 1] = current
# insertion_passes.py
# A copy of insertion_sort that prints the list after each item is placed.


def insertion_passes(nums):
    for i in range(1, len(nums)):
        current = nums[i]
        j = i - 1
        while j >= 0 and nums[j] > current:
            nums[j + 1] = nums[j]
            j -= 1
        nums[j + 1] = current
        print("place", current, nums)


insertion_passes([42, 18, 65, 7, 30])
icurrentSorted part beforeShifted rightList after
1184242[18, 42, 65, 7, 30]
26518, 42nothing[18, 42, 65, 7, 30]
3718, 42, 6565, 42, 18[7, 18, 42, 65, 30]
4307, 18, 42, 6565, 42[7, 18, 30, 42, 65]
TRACE INSERTION_PASSES.PY
  • Read the question.
  • Tap your answer.
When 65 is placed, how many items shift?
When 7 is placed, how many items shift right?
After 7 is placed, is 42 in its final place?
place 18 [18, 42, 65, 7, 30]
place 65 [18, 42, 65, 7, 30]
place 7 [7, 18, 42, 65, 30]
place 30 [7, 18, 30, 42, 65]
PUT THE STEPS OF PLACING ONE ITEM IN ORDER
  • ?Copy the next unsorted item into current
  • ?Start j at the last item of the sorted part
  • ?While nums[j] is larger than current, shift it one place right
  • ?Move j one place left after each shift
  • ?Drop current into the gap at j + 1
WHY THIS EXERCISEInsertion sort saves the item, shifts larger sorted items right, then drops the item into the gap.

Count the comparisons

This counting copy runs insertion sort on the catalog grams, then again on the list it just sorted. Made-up data from the FieldSim story.

# count_insertion.py
# A copy of insertion_sort that counts comparisons.
from field_data import CATALOG


def insertion_count(nums):
    """Sorts nums in place and gives back the number of comparisons."""
    comparisons = 0
    for i in range(1, len(nums)):
        current = nums[i]
        j = i - 1
        while j >= 0:
            comparisons += 1
            if nums[j] > current:
                nums[j + 1] = nums[j]
                j -= 1
            else:
                break
        nums[j + 1] = current
    return comparisons


grams = []
for label, kind, g in CATALOG:
    grams.append(g)
print(insertion_count(grams))
print(grams)
print(insertion_count(grams))
PREDICT COUNT_INSERTION.PY
  • Read the question.
  • Tap your answer.
On the catalog grams, does insertion sort make more or fewer comparisons than selection sort's 45?
On the already sorted list, how many comparisons?
28
[7, 12, 18, 25, 30, 39, 42, 51, 65, 88]
9
ListSelection sort comparisonsInsertion sort comparisons
Catalog grams (unsorted)4528
Already sorted459
At your computer
1. Type insertion_passes.py in your fieldsim folder, save it and run it.
2. Change one thing: sort [7, 18, 30, 42, 65], which is already sorted. Predict how many items shift, then run.
3. Break it on purpose: change the last line inside the loop from nums[j + 1] = current to nums[j] = current. Run it and look for numbers that disappeared.
4. Put the + 1 back and run once more.

This is the run for step 3, in a short file with the same mistake.

# insertion_oops.py


def insertion_oops(nums):
    for i in range(1, len(nums)):
        current = nums[i]
        j = i - 1
        while j >= 0 and nums[j] > current:
            nums[j + 1] = nums[j]
            j -= 1
        nums[j] = current


nums = [42, 18, 65, 7, 30]
insertion_oops(nums)
print(nums)
[42, 42, 42, 65, 7]
READ THE BROKEN RUN
  • Read the question.
  • Tap your answer.
The start list was 42, 18, 65, 7, 30. Which two numbers are missing from the output?
What kind of error is it?
StatementTrue or false?
Insertion sort shifts larger items right to make room.?
Insertion sort puts each item in its final place straight away.?
On a sorted list, insertion sort did fewer comparisons than selection sort.?
Both sorts made the same number of comparisons on the catalog grams.?
WHY THIS EXERCISEInsertion sort stops shifting at the first smaller item, so it does less work when the list is nearly sorted.

Same five numbers, a different way to sort them, and a very different count. Tomorrow you sort Sample objects.

← Wednesday