Quiz 2
Registry Synced

Week 5: Insertion Sort

1887 words
9 min read

Reading compass

Now · 1. Motivation: Why Sort?

Week 5: Insertion Sort

BSCS1001 — IIT Madras BS Degree Prerequisite: Topic 09 (Lists & Collections) Cross-links: BSCS1002-Python (Week 7 — Sorting), BSCS2002-PDSA (Week 5 — Insertion Sort)

1. Motivation: Why Sort?

A sorted list makes many problems much easier:
ProblemWithout SortingWith Sorting
Find top K valuesScan entire list K timesJust take first K elements
Find duplicatesCompare every pair (O(N²))Check adjacent elements (O(N))
Group by percentilesComplex calculationsDivide sorted list into quarters
Find medianNeed complex algorithmMiddle element of sorted list
Binary searchNot possibleFind in O(log N) time
Real-world analogy: Finding a word in a dictionary. If the words weren't sorted, you'd have to check every page. Because they are sorted, you can flip to roughly the right spot.

2. The Insertion Sort Idea

Insertion sort is one of the simplest sorting algorithms. The idea:
"Repeatedly insert the next element into a sorted list." (Diagram)

Key Insight: The Invariant

After each step, the "second list" is always sorted.
  • [] is sorted (trivially)
  • Inserting into a sorted list produces a sorted list
  • Therefore, after processing all elements, the result is sorted This is called a loop invariant — a property that holds true before and after each iteration.

3. Inserting into a Sorted List

Before we sort, we need to solve a simpler problem: insert one element into a sorted list while keeping it sorted.

The Algorithm

pseudo
Procedure SortedListInsert(L, x)
    newList = []
    inserted = False
    foreach z in L {
        if (not(inserted)) {
            if (x < z) {
                newList = newList ++ [x]
                inserted = True
            }
        }
        newList = newList ++ [z]
    }
    // If x is larger than everything, append at end
    if (not(inserted)) {
        newList = newList ++ [x]
    }
    return(newList)
End SortedListInsert

How It Works

  1. Start with an empty new list
  2. Iterate through the sorted list L
  3. If we haven't inserted x yet, check if x should go before current z
  4. If yes, insert x first, then z
  5. If no, just add z
  6. At the end, if x wasn't inserted (it's larger than all elements), append it

Tracing: Insert 5 into [3, 7, 9]

Stepzx < z?inserted?newListAction
InitFalse[]
Iter 135<3? ❌False[3]Just add 3
Iter 275<7? ✅→ True[3, 5]Insert x before 7
Iter 2 cont7True[3, 5, 7]Then add 7
Iter 39True[3, 5, 7, 9]Just add 9
EndTrue (inserted)[3, 5, 7, 9]Return

Boundary Cases

CaseInputProcessResult
Empty listL=[], x=5inserted stays False, append at end[5]
x is smallestL=[3,7,9], x=11<3 at first step, insert before 3[1,3,7,9]
x is largestL=[3,7,9], x=10inserted stays False until end, append[3,7,9,10]
DuplicateL=[3,7,9], x=77<3? No; 7<7? No (not less than); 7<9? Yes[3,7,7,9]

4. Full Insertion Sort Algorithm

The Main Algorithm

pseudo
Procedure InsertionSort(L)
    sortedList = []
    foreach z in L {
        sortedList = SortedListInsert(sortedList, z)
    }
    return(sortedList)
End InsertionSort

Complete Pseudocode (Both Procedures)

pseudo
Procedure SortedListInsert(L, x)
    newList = []
    inserted = False
    foreach z in L {
        if (not(inserted)) {
            if (x < z) {
                newList = newList ++ [x]
                inserted = True
            }
        }
        newList = newList ++ [z]
    }
    if (not(inserted)) {
        newList = newList ++ [x]
    }
    return(newList)
End SortedListInsert
Procedure InsertionSort(L)
    sortedList = []
    foreach z in L {
        sortedList = SortedListInsert(sortedList, z)
    }
    return(sortedList)
End InsertionSort

5. Step-by-Step Tracing

Sorting [7, 3, 9, 1]

Step 1: Take 7, insert into []
  • SortedListInsert([], 7): empty list, append 7
  • sortedList = [7] Step 2: Take 3, insert into [7]
  • L=[7], x=3: compare 3<7 → insert before 7
  • sortedList = [3, 7] Step 3: Take 9, insert into [3, 7]
  • 9<3? No. 9<7? No. End: append 9.
  • sortedList = [3, 7, 9] Step 4: Take 1, insert into [3, 7, 9]
  • 1<3? Yes → insert before 3
  • sortedList = [1, 3, 7, 9]

Complete Tracing Table

IterationOriginal LzSorted List BeforeSorted List After
Init[7, 3, 9, 1][][]
1[7, 3, 9, 1]7[][7]
2[7, 3, 9, 1]3[7][3, 7]
3[7, 3, 9, 1]9[3, 7][3, 7, 9]
4[7, 3, 9, 1]1[3, 7, 9][1, 3, 7, 9]

Another Example: [5, 2, 8, 2, 9]

StepzSorted List BeforeInsert ProcessSorted List After
15[]Append[5]
22[5]2<5 → insert[2, 5]
38[2, 5]8>5 → append[2, 5, 8]
42[2, 5, 8]2<2? No; 2<5? Yes → insert[2, 2, 5, 8]
59[2, 2, 5, 8]9>8 → append[2, 2, 5, 8, 9]
Notice: Duplicates are preserved. Insertion sort is a stable sorting algorithm.

6. Boundary Conditions

Case 1: Empty List

pseudo
InsertionSort([])
StepzSorted BeforeActionSorted After
Init[][]
Result: [] (empty list stays empty)

Case 2: Single Element

pseudo
InsertionSort([5])
StepzSorted BeforeActionSorted After
15[]Append[5]
Result: [5] (single element is trivially sorted)

Case 3: Already Sorted

pseudo
InsertionSort([1, 2, 3, 4])
StepzSorted BeforeActionSorted After
11[]Append[1]
22[1]2>1 → append[1, 2]
33[1, 2]3>2 → append[1, 2, 3]
44[1, 2, 3]4>3 → append[1, 2, 3, 4]
Each step just appends — O(N) time for already sorted input.

Case 4: Reverse Sorted (Worst Case)

pseudo
InsertionSort([4, 3, 2, 1])
StepzSorted BeforeActionSorted After
14[]Append[4]
23[4]3<4 → insert at front[3, 4]
32[3, 4]2<3 → insert at front[2, 3, 4]
41[2, 3, 4]1<2 → insert at front[1, 2, 3, 4]
Each step inserts at the front — O(N²) time for reverse sorted input.

7. Recursive Insertion Sort

Insertion sort can also be defined recursively (see Week 9 for more on recursion):
pseudo
Procedure InsertionSortRec(L)
    if (length(L) <= 1) {
        return(L)
    }
    else {
        // Sort rest of list, then insert first element
        return(SortedListInsert(
            InsertionSortRec(rest(L)),
            first(L)
        ))
    }
End InsertionSortRec

How It Works

For L = [7, 3, 9, 1]:
  1. InsertionSortRec([7, 3, 9, 1])
  2. SortedListInsert(InsertionSortRec([3, 9, 1]), 7)
  3. → → SortedListInsert(SortedListInsert(InsertionSortRec([9, 1]), 3), 7)
  4. → → → continues until base case

8. Complexity Analysis

Time Complexity

CaseComparisonsShiftsComplexity
Best (already sorted)N-10O(N)
Average~N²/4~N²/4O(N²)
Worst (reverse sorted)N(N-1)/2N(N-1)/2O(N²)

Space Complexity

AspectDetail
Extra spaceO(N) — we create a new sorted list
In-place versionPossible but not used in this course
Total spaceO(N) for input + O(N) for output = O(N)

Comparison with Other Sorts

AlgorithmBest CaseAverage CaseWorst CaseSpace
Insertion SortO(N)O(N²)O(N²)O(N)
Selection SortO(N²)O(N²)O(N²)O(1)
Merge SortO(N log N)O(N log N)O(N log N)O(N)
Quick SortO(N log N)O(N log N)O(N²)O(log N)
Note: Insertion sort is not the fastest, but it's the simplest and works well for small or nearly-sorted lists.

9. Comparison: Sorting Approaches

Insertion Sort vs Other Simple Sorts

AspectInsertion SortSelection SortBubble Sort
IdeaBuild sorted list by insertingFind min, swap to frontSwap adjacent out-of-order pairs
Best caseO(N) — already sortedO(N²) — alwaysO(N) — with optimization
Worst caseO(N²)O(N²)O(N²)
Stable?✅ Yes❌ No (typical)✅ Yes
Adaptive?✅ Yes (faster if partially sorted)❌ No✅ Yes
Simple?✅ Very✅ Yes✅ Yes

When to Use Insertion Sort

(Diagram)

10. Practice Questions

Basic Questions

Q1. What is the basic idea of insertion sort?
Show Answer
Insertion sort repeatedly takes the next element from the original list and inserts it into the correct position in a new sorted list. The invariant is that the new list is always sorted. Q2. Trace insertion sort on [4, 1, 3]. Show the sorted list after each step. Show Answer
StepzSorted BeforeActionSorted After
14[]Append[4]
21[4]1<4 → insert front[1, 4]
33[1, 4]3>1, 3<4 → insert[1, 3, 4]
Final: [1, 3, 4] Q3. What happens in SortedListInsert when x is larger than all elements in L? Show Answer
The inserted flag stays False throughout the loop. After the loop, the check if (not(inserted)) is True, so x is appended at the end. Q4. What is the best-case input for insertion sort? What is the time complexity? Show Answer
Best case: An already-sorted list. Each element just gets appended (no shifting needed). Time complexity: O(N).

Intermediate Questions

Q5. Trace SortedListInsert for L=[2, 5, 8], x=6.
Show Answer
zx < z?inserted?newList
26<2? ❌False[2]
56<5? ❌False[2, 5]
86<8? ✅→ True[2, 5, 6] → then [2, 5, 6, 8]
(after loop)True[2, 5, 6, 8]
Result: [2, 5, 6, 8] Q6. Trace the full insertion sort on [9, 5, 7]. Show Answer
StepzSorted BeforeInsert ActionSorted After
19[]Append[9]
25[9]5<9 → insert front[5, 9]
37[5, 9]7>5, 7<9 → insert[5, 7, 9]
Final: [5, 7, 9] Q7. What is a loop invariant? What is the loop invariant of insertion sort? Show Answer
A loop invariant is a property that holds true before and after each iteration of a loop.
For insertion sort, the invariant is: After processing k elements, the sorted list contains those k elements in sorted order. This is true at the start (empty list is sorted), remains true after each insertion, and when all N elements are processed, the full list is sorted. Q8. How would you sort a list in descending order using insertion sort? Show Answer
Change the comparison in SortedListInsert from x < z to x > z:
sql
if (x > z) {    // Changed from < to >
    newList = newList ++ [x]
    inserted = True
}
This inserts larger elements before smaller ones, producing descending order.

Advanced Questions

Q9. Explain why insertion sort is "adaptive." What does this mean?
Show Answer
Adaptive means the algorithm performs better when the input is partially sorted (has existing order). Insertion sort is adaptive because:
  • For an already-sorted list, each insertion just appends (O(N))
  • For a nearly-sorted list, few elements need to be shifted far
  • The number of comparisons equals the number of inversions (out-of-order pairs)
This makes insertion sort excellent for "almost sorted" data. Q10. Compare insertion sort with selection sort. Which is better and when? Show Answer
AspectInsertion SortSelection Sort
Best caseO(N) — already sortedO(N²) — always
Worst caseO(N²)O(N²)
Adaptive✅ Yes❌ No
Stable✅ Yes❌ No (typical)
SwapsO(N²) (many shifts)O(N) (minimal swaps)
When to use: Insertion sort for small or nearly-sorted data; selection sort when writes are expensive (e.g., EEPROM). Q11. Trace insertion sort on [3, 1, 4, 1, 5, 9, 2, 6] for the first 4 elements only. Show Answer
StepzSorted BeforeInsert ActionSorted After
13[]Append[3]
21[3]1<3 → front[1, 3]
34[1, 3]4>3 → append[1, 3, 4]
41[1, 3, 4]1<1? No; 1<3? Yes → insert[1, 1, 3, 4]
After 4 elements: [1, 1, 3, 4] Q12. Write a version of insertion sort that sorts a list of student records by their Maths marks (ascending). Show Answer
pseudo
Procedure InsertionSortByMarks(L)
    sortedList = []
    foreach z in L {
        sortedList = SortedListInsertByMarks(sortedList, z)
    }
    return(sortedList)
End InsertionSortByMarks

Procedure SortedListInsertByMarks(L, x)
    newList = []
    inserted = False
    foreach z in L {
        if (not(inserted)) {
            if (x.Maths < z.Maths) {     // Compare Maths field
                newList = newList ++ [x]
                inserted = True
            }
        }
        newList = newList ++ [z]
    }
    if (not(inserted)) {
        newList = newList ++ [x]
    }
    return(newList)
End SortedListInsertByMarks

📚 Cross-References

CourseTopicConnection
BSCS1002 (Python)Week 7 — SortingPython sorted() and list .sort()
BSCS2002 (PDSA)Week 5 — SortingInsertion sort analysis, other sorts
BSCS2002 (PDSA)Week 6 — ComplexityTime/space complexity

Quiz Tip: Insertion sort tracing questions are very common. Practice with different inputs until you're fast! Join Discord PreviousLists & CollectionsNextDictionaries
Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.