Neural Sync Active
Week 5: Insertion Sort
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:
| Problem | Without Sorting | With Sorting |
|---|---|---|
| Find top K values | Scan entire list K times | Just take first K elements |
| Find duplicates | Compare every pair (O(N²)) | Check adjacent elements (O(N)) |
| Group by percentiles | Complex calculations | Divide sorted list into quarters |
| Find median | Need complex algorithm | Middle element of sorted list |
| Binary search | Not possible | Find 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
pseudoProcedure 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
- Start with an empty new list
- Iterate through the sorted list L
- If we haven't inserted x yet, check if x should go before current z
- If yes, insert x first, then z
- If no, just add z
- At the end, if x wasn't inserted (it's larger than all elements), append it
Tracing: Insert 5 into [3, 7, 9]
| Step | z | x < z? | inserted? | newList | Action |
|---|---|---|---|---|---|
| Init | — | — | False | [] | — |
| Iter 1 | 3 | 5<3? ❌ | False | [3] | Just add 3 |
| Iter 2 | 7 | 5<7? ✅ | → True | [3, 5] | Insert x before 7 |
| Iter 2 cont | 7 | — | True | [3, 5, 7] | Then add 7 |
| Iter 3 | 9 | — | True | [3, 5, 7, 9] | Just add 9 |
| End | — | — | True (inserted) | [3, 5, 7, 9] | Return |
Boundary Cases
| Case | Input | Process | Result |
|---|---|---|---|
| Empty list | L=[], x=5 | inserted stays False, append at end | [5] |
| x is smallest | L=[3,7,9], x=1 | 1<3 at first step, insert before 3 | [1,3,7,9] |
| x is largest | L=[3,7,9], x=10 | inserted stays False until end, append | [3,7,9,10] |
| Duplicate | L=[3,7,9], x=7 | 7<3? No; 7<7? No (not less than); 7<9? Yes | [3,7,7,9] |
4. Full Insertion Sort Algorithm
The Main Algorithm
pseudoProcedure InsertionSort(L) sortedList = [] foreach z in L { sortedList = SortedListInsert(sortedList, z) } return(sortedList) End InsertionSort
Complete Pseudocode (Both Procedures)
pseudoProcedure 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
| Iteration | Original L | z | Sorted List Before | Sorted 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]
| Step | z | Sorted List Before | Insert Process | Sorted List After |
|---|---|---|---|---|
| 1 | 5 | [] | Append | [5] |
| 2 | 2 | [5] | 2<5 → insert | [2, 5] |
| 3 | 8 | [2, 5] | 8>5 → append | [2, 5, 8] |
| 4 | 2 | [2, 5, 8] | 2<2? No; 2<5? Yes → insert | [2, 2, 5, 8] |
| 5 | 9 | [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
pseudoInsertionSort([])
| Step | z | Sorted Before | Action | Sorted After |
|---|---|---|---|---|
| Init | — | [] | — | [] |
Result:
[] (empty list stays empty)Case 2: Single Element
pseudoInsertionSort([5])
| Step | z | Sorted Before | Action | Sorted After |
|---|---|---|---|---|
| 1 | 5 | [] | Append | [5] |
Result:
[5] (single element is trivially sorted)Case 3: Already Sorted
pseudoInsertionSort([1, 2, 3, 4])
| Step | z | Sorted Before | Action | Sorted After |
|---|---|---|---|---|
| 1 | 1 | [] | Append | [1] |
| 2 | 2 | [1] | 2>1 → append | [1, 2] |
| 3 | 3 | [1, 2] | 3>2 → append | [1, 2, 3] |
| 4 | 4 | [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)
pseudoInsertionSort([4, 3, 2, 1])
| Step | z | Sorted Before | Action | Sorted After |
|---|---|---|---|---|
| 1 | 4 | [] | Append | [4] |
| 2 | 3 | [4] | 3<4 → insert at front | [3, 4] |
| 3 | 2 | [3, 4] | 2<3 → insert at front | [2, 3, 4] |
| 4 | 1 | [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):
pseudoProcedure 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]:
InsertionSortRec([7, 3, 9, 1])- →
SortedListInsert(InsertionSortRec([3, 9, 1]), 7) - → →
SortedListInsert(SortedListInsert(InsertionSortRec([9, 1]), 3), 7) - → → → continues until base case
8. Complexity Analysis
Time Complexity
| Case | Comparisons | Shifts | Complexity |
|---|---|---|---|
| Best (already sorted) | N-1 | 0 | O(N) |
| Average | ~N²/4 | ~N²/4 | O(N²) |
| Worst (reverse sorted) | N(N-1)/2 | N(N-1)/2 | O(N²) |
Space Complexity
| Aspect | Detail |
|---|---|
| Extra space | O(N) — we create a new sorted list |
| In-place version | Possible but not used in this course |
| Total space | O(N) for input + O(N) for output = O(N) |
Comparison with Other Sorts
| Algorithm | Best Case | Average Case | Worst Case | Space |
|---|---|---|---|---|
| Insertion Sort | O(N) | O(N²) | O(N²) | O(N) |
| Selection Sort | O(N²) | O(N²) | O(N²) | O(1) |
| Merge Sort | O(N log N) | O(N log N) | O(N log N) | O(N) |
| Quick Sort | O(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
| Aspect | Insertion Sort | Selection Sort | Bubble Sort |
|---|---|---|---|
| Idea | Build sorted list by inserting | Find min, swap to front | Swap adjacent out-of-order pairs |
| Best case | O(N) — already sorted | O(N²) — always | O(N) — with optimization |
| Worst case | O(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 AnswerInsertion 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
| Step | z | Sorted Before | Action | Sorted After |
|---|---|---|---|---|
| 1 | 4 | [] | Append | [4] |
| 2 | 1 | [4] | 1<4 → insert front | [1, 4] |
| 3 | 3 | [1, 4] | 3>1, 3<4 → insert | [1, 3, 4] |
Final:[1, 3, 4]Q3. What happens inSortedListInsertwhen x is larger than all elements in L? Show AnswerTheinsertedflag stays False throughout the loop. After the loop, the checkif (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 AnswerBest 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
| z | x < z? | inserted? | newList |
|---|---|---|---|
| 2 | 6<2? ❌ | False | [2] |
| 5 | 6<5? ❌ | False | [2, 5] |
| 8 | 6<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
| Step | z | Sorted Before | Insert Action | Sorted After |
|---|---|---|---|---|
| 1 | 9 | [] | Append | [9] |
| 2 | 5 | [9] | 5<9 → insert front | [5, 9] |
| 3 | 7 | [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 AnswerA 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 AnswerChange the comparison inSortedListInsertfromx < ztox > z:sqlif (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 AnswerAdaptive 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
| Aspect | Insertion Sort | Selection Sort |
|---|---|---|
| Best case | O(N) — already sorted | O(N²) — always |
| Worst case | O(N²) | O(N²) |
| Adaptive | ✅ Yes | ❌ No |
| Stable | ✅ Yes | ❌ No (typical) |
| Swaps | O(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
| Step | z | Sorted Before | Insert Action | Sorted After |
|---|---|---|---|---|
| 1 | 3 | [] | Append | [3] |
| 2 | 1 | [3] | 1<3 → front | [1, 3] |
| 3 | 4 | [1, 3] | 4>3 → append | [1, 3, 4] |
| 4 | 1 | [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 AnswerpseudoProcedure 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
| Course | Topic | Connection |
|---|---|---|
| BSCS1002 (Python) | Week 7 — Sorting | Python sorted() and list .sort() |
| BSCS2002 (PDSA) | Week 5 — Sorting | Insertion sort analysis, other sorts |
| BSCS2002 (PDSA) | Week 6 — Complexity | Time/space complexity |
Next Topic: 11 — DictionariesQuiz Tip: Insertion sort tracing questions are very common. Practice with different inputs until you're fast! Join Discord PreviousLists & CollectionsNextDictionaries