Insertion Sort Algorithm in DSA Rust - Time & Space Complexity
We want to understand how the time taken by the Insertion Sort algorithm changes as the list size grows.
How does the number of steps increase when sorting more items?
Analyze the time complexity of the following code snippet.
fn insertion_sort(arr: &mut [i32]) {
for i in 1..arr.len() {
let key = arr[i];
let mut j = i;
while j > 0 && arr[j - 1] > key {
arr[j] = arr[j - 1];
j -= 1;
}
arr[j] = key;
}
}
This code sorts an array by inserting each element into its correct place among the already sorted elements to its left.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The inner while loop that shifts elements to insert the key in the right position.
- How many times: The outer for loop runs once for each element except the first, and the inner loop can run up to i times for each i.
As the list size grows, the number of comparisons and shifts grows roughly with the square of the size in the worst case.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 45 comparisons and shifts |
| 100 | About 4,950 comparisons and shifts |
| 1000 | About 499,500 comparisons and shifts |
Pattern observation: The operations grow roughly by the square of the input size, so doubling the input size makes the work about four times bigger.
Time Complexity: O(n²)
This means the time taken grows roughly with the square of the number of items to sort.
[X] Wrong: "Insertion Sort always takes the same time no matter the input order."
[OK] Correct: If the list is already mostly sorted, Insertion Sort runs much faster, close to linear time, because fewer shifts are needed.
Understanding Insertion Sort's time complexity helps you compare simple sorting methods and recognize when they are efficient or slow in real tasks.
"What if we changed the array to be already sorted? How would the time complexity change?"
Practice
Insertion Sort algorithm?Solution
Step 1: Understand insertion sort process
Insertion sort builds the sorted list by taking one element at a time and placing it in the correct position among the already sorted elements.Step 2: Compare with other sorting methods
Unlike divide and conquer (merge sort) or swapping adjacent elements (bubble sort), insertion sort inserts elements directly into their correct place.Final Answer:
Build the sorted array one element at a time by inserting elements in their correct position -> Option BQuick Check:
Insertion sort = Insert elements correctly one by one [OK]
- Confusing insertion sort with bubble sort
- Thinking it divides array like merge sort
- Assuming it swaps only smallest elements
Solution
Step 1: Identify insertion sort loop start
Insertion sort starts from the second element (index 1) because the first element is considered sorted.Step 2: Check Rust range syntax
The range 1..arr.len() correctly iterates from index 1 to the last index (exclusive of arr.len()).Final Answer:
for i in 1..arr.len() { -> Option AQuick Check:
Start loop at 1 for insertion sort [OK]
- Starting loop at 0 instead of 1
- Using reversed range incorrectly
- Off-by-one errors in range
arr = [4, 3, 1, 5]?
let mut arr = vec![4, 3, 1, 5];
for i in 1..arr.len() {
let key = arr[i];
let mut j = i;
while j > 0 && arr[j - 1] > key {
arr[j] = arr[j - 1];
j -= 1;
}
arr[j] = key;
}
println!("{:?}", arr);Solution
Step 1: Trace first iteration (i=1)
key=3, compare with 4; 4 > 3 so shift 4 right, insert 3 at index 0. Array: [3,4,1,5]Step 2: Trace second iteration (i=2)
key=1, compare with 4 and 3; both >1 so shift them right, insert 1 at index 0. Array: [1,3,4,5]Step 3: Trace third iteration (i=3)
key=5, compare with 4; 4 < 5 so no shift, insert 5 at index 3. Array unchanged: [1,3,4,5]Final Answer:
[1, 3, 4, 5] -> Option CQuick Check:
Sorted array after insertion sort = [1, 3, 4, 5] [OK]
- Not shifting elements correctly
- Off-by-one errors in while loop
- Printing original array without sorting
let mut arr = vec![2, 5, 3];
for i in 1..arr.len() {
let key = arr[i];
let mut j = i - 1;
while j >= 0 && arr[j] > key {
arr[j + 1] = arr[j];
j -= 1;
}
arr[j + 1] = key;
}Solution
Step 1: Analyze variable j type and condition
In Rust, usize is unsigned, so j >= 0 is always true, causing infinite loop when j underflows.Step 2: Understand while loop behavior
When j reaches 0 and decrements, it wraps to a large number, so loop never ends.Final Answer:
The variable j is unsigned and j >= 0 check causes infinite loop -> Option DQuick Check:
Unsigned j with j >= 0 causes infinite loop [OK]
- Ignoring unsigned integer wrap-around
- Assuming j can be negative
- Not using a different loop condition
Vec<(i32, String)> by the integer value. Which change is needed in the comparison inside the while loop?Solution
Step 1: Understand tuple sorting by first element
To sort by the integer part of the tuple, compare the first element (.0) of each tuple.Step 2: Modify comparison in while loop
Replacearr[j - 1] > keywitharr[j - 1].0 > key.0to compare integers correctly.Final Answer:
Changearr[j - 1] > keytoarr[j - 1].0 > key.0-> Option AQuick Check:
Compare tuple first elements for sorting [OK]
- Comparing string part instead of integer
- Assuming tuples compare by second element automatically
- Using length of string for comparison
Ready to prove it?
Pass the test and this pattern moves unknown
