📌 Snapshot
- Bubble, selection and insertion sort traced pass by pass, with time complexity explained simply.
- Why sorting pays off, and the exact idea, code and per pass table for each of the three algorithms.
- A side by side comparison of swaps, shifts and passes, and the reason all three are quadratic.
- Counting comparisons and tracing lists after k passes, the two skills CUET sorting questions rely on.
📖 Detailed Notes
Written and reviewed by Rohit Singh, Computer Science & Commerce faculty at UniDrill (MCA, Osmania University · 6 years teaching). Based on NCERT Computer Science Class XII, Chapter 5.
Why sort at all?
Suppose a list holds 1,00,000 names. If it is jumbled, finding one name may mean checking every single entry, up to 1,00,000 checks. If the same list is sorted, a method called binary search needs at most 17 checks. Sorting costs effort once, and every search afterwards gets dramatically cheaper. That upfront cost is worth paying when a collection is big and searched often.
Sorting means arranging the elements of a collection in a particular order: ascending (small to large), descending (large to small) or alphabetical. A dictionary is sorted alphabetically, an exam hall by roll number, a line of students by height. This chapter covers three simple algorithms and then asks how fast they are.
Throughout, the example list is numList = [8, 7, 13, 1, -9, 4], sorted into ascending order. A pass is one full sweep through the list (or the part of it still being worked on), and a swap exchanges the positions of two elements.
Bubble sort
The idea. Compare neighbours and swap them if they are in the wrong order. After one pass, the largest element has been carried all the way to the end, like a bubble rising. That element is now in its final place and is left alone in later passes. A list of n elements needs n − 1 passes.
Here is pass 1 in detail. Each row compares one neighbouring pair.
| Comparison | Pair compared | Swap? | List afterwards |
|---|---|---|---|
| 1 | 8 and 7 |
Yes | [7, 8, 13, 1, -9, 4] |
| 2 | 8 and 13 |
No | [7, 8, 13, 1, -9, 4] |
| 3 | 13 and 1 |
Yes | [7, 8, 1, 13, -9, 4] |
| 4 | 13 and -9 |
Yes | [7, 8, 1, -9, 13, 4] |
| 5 | 13 and 4 |
Yes | [7, 8, 1, -9, 4, 13] |
The 13 is picked up at the third comparison and carried to the end. Every later pass works on a shorter list, because the sorted end is excluded. The full run looks like this.
| Pass | List at the end of the pass | Comparisons | Swaps | Now in final place |
|---|---|---|---|---|
| 1 | [7, 8, 1, -9, 4, 13] |
5 | 4 | 13 |
| 2 | [7, 1, -9, 4, 8, 13] |
4 | 3 | 8 |
| 3 | [1, -9, 4, 7, 8, 13] |
3 | 3 | 7 |
| 4 | [-9, 1, 4, 7, 8, 13] |
2 | 1 | 4 |
| 5 | [-9, 1, 4, 7, 8, 13] |
1 | 0 | 1 |
The comparisons shrink from 5 to 1, which is why the inner loop stops at n - i - 1. There are 5 + 4 + 3 + 2 + 1 = 15 comparisons in all, and the same count appears for any list of 6 elements.
| Code |
|---|
def bubble_Sort(list1): |
n = len(list1) |
for i in range(n - 1): |
for j in range(0, n - i - 1): |
if list1[j] > list1[j + 1]: |
list1[j], list1[j + 1] = list1[j + 1], list1[j] |
The outer loop counts passes. The inner loop makes the comparisons, and list1[j], list1[j + 1] = list1[j + 1], list1[j] swaps two elements in one line. Writing range(n) for the outer loop also works, because the extra last pass has an empty inner loop and does nothing. The common wrong step is an inner loop bound of n - 1 instead of n - i - 1: it keeps comparing elements that are already in their final place.
Worked example: bubble sort of [5, 1, 4, 2, 8]. What does the list look like after each pass?
| Pass | List at the end of the pass | Comparisons | Swaps | Now in final place |
|---|---|---|---|---|
| 1 | [1, 4, 2, 5, 8] |
4 | 3 | 8 |
| 2 | [1, 2, 4, 5, 8] |
3 | 1 | 5 |
| 3 | [1, 2, 4, 5, 8] |
2 | 0 | 4 |
| 4 | [1, 2, 4, 5, 8] |
1 | 0 | 2 |
After pass 2 the last two elements are 5 and 8. Passes 3 and 4 find nothing to swap, because the list became sorted early. The plain algorithm still carries out all n − 1 passes.
Pause and predict: how many swaps does bubble sort make on the reversed list [4, 3, 2, 1]?
Check your answer: 6. Pass 1 makes 3 swaps, pass 2 makes 2 and pass 3 makes 1. A reversed list is the worst case, and every comparison leads to a swap: 3 + 2 + 1 = 6.
Selection sort
The idea. Split the list into a sorted part on the left (empty at first) and an unsorted part on the right. In every pass, scan the whole unsorted part to find its smallest element, and swap that element with the leftmost element of the unsorted part. The sorted part grows by one each pass, and a list of n elements needs n − 1 passes. At most one swap happens per pass, and it comes after the scan, not during it.
| Pass | Smallest of the unsorted part | Swap | List after the pass |
|---|---|---|---|
| 1 | -9 at index 4 |
Swap 8 with -9 |
[-9, 7, 13, 1, 8, 4] |
| 2 | 1 at index 3 |
Swap 7 with 1 |
[-9, 1, 13, 7, 8, 4] |
| 3 | 4 at index 5 |
Swap 13 with 4 |
[-9, 1, 4, 7, 8, 13] |
| 4 | 7 at index 3 |
No swap (flag stays 0) | [-9, 1, 4, 7, 8, 13] |
| 5 | 8 at index 4 |
No swap (flag stays 0) | [-9, 1, 4, 7, 8, 13] |
Passes 4 and 5 found the smallest element already sitting at the start of the unsorted part, so nothing moved.
| Code |
|---|
def selection_Sort(list2): |
n = len(list2) |
for i in range(n - 1): |
min_idx = i |
flag = 0 |
for j in range(i + 1, n): |
if list2[j] < list2[min_idx]: |
min_idx = j |
flag = 1 |
if flag == 1: |
list2[min_idx], list2[i] = list2[i], list2[min_idx] |
The variable min_idx remembers the position of the smallest value seen so far, and flag records whether a smaller element was found. The swap line runs only when flag is 1, once per pass at most.
Worked example: selection sort of [29, 10, 14, 37, 13]. Four passes are needed.
| Pass | Smallest of the unsorted part | Swap | List after the pass |
|---|---|---|---|
| 1 | 10 at index 1 |
Swap 29 with 10 |
[10, 29, 14, 37, 13] |
| 2 | 13 at index 4 |
Swap 29 with 13 |
[10, 13, 14, 37, 29] |
| 3 | 14 at index 2 |
No swap (flag stays 0) | [10, 13, 14, 37, 29] |
| 4 | 29 at index 4 |
Swap 37 with 29 |
[10, 13, 14, 29, 37] |
Pass 3 changes nothing because 14 is already in place. The whole sort used 3 swaps.
Pause and predict: how many swaps does selection sort make on an already sorted list?
Check your answer: None. In every pass the smallest unsorted element is already at the left of the unsorted part, so flag stays 0 and no swap is executed. The scanning still happens in full.
Insertion sort
The idea. Again the list has a sorted part on the left, but now it starts with just the first element. In each pass, take the first element of the unsorted part and call it temp. Compare temp with the sorted elements from right to left. Each sorted element bigger than temp is shifted one place to the right to open a gap, and temp drops into the gap. This is how most people sort playing cards in hand.
| Pass | temp (element to insert) | Elements shifted right | temp placed at | List after the pass |
|---|---|---|---|---|
| 1 | 7 |
1 | Index 0 | [7, 8, 13, 1, -9, 4] |
| 2 | 13 |
0 | Index 2 | [7, 8, 13, 1, -9, 4] |
| 3 | 1 |
3 | Index 0 | [1, 7, 8, 13, -9, 4] |
| 4 | -9 |
4 | Index 0 | [-9, 1, 7, 8, 13, 4] |
| 5 | 4 |
3 | Index 2 | [-9, 1, 4, 7, 8, 13] |
In pass 2 the element 13 is already bigger than everything on its left, so nothing shifts. Pass 4 is the costliest: -9 is smaller than all four sorted elements, so all four shift.
| Code |
|---|
def insertion_Sort(list3): |
n = len(list3) |
for i in range(1, n): |
temp = list3[i] |
j = i - 1 |
while j >= 0 and list3[j] > temp: |
list3[j + 1] = list3[j] |
j = j - 1 |
list3[j + 1] = temp |
The condition j >= 0 stops the loop at the left edge. The line list3[j + 1] = list3[j] is the shift, and the last line places temp in the gap. Notice that elements are shifted, not swapped. temp is written once per pass, at the end.
Worked example: insertion sort of [12, 11, 13, 5, 6].
| Pass | temp (element to insert) | Elements shifted right | temp placed at | List after the pass |
|---|---|---|---|---|
| 1 | 11 |
1 | Index 0 | [11, 12, 13, 5, 6] |
| 2 | 13 |
0 | Index 2 | [11, 12, 13, 5, 6] |
| 3 | 5 |
3 | Index 0 | [5, 11, 12, 13, 6] |
| 4 | 6 |
3 | Index 1 | [5, 6, 11, 12, 13] |
After pass 3 the list is [5, 11, 12, 13, 6]: the first four elements are sorted and 6 is still waiting.
The three sorts side by side
| Feature | Bubble sort | Selection sort | Insertion sort |
|---|---|---|---|
| Core move | Compare neighbours, swap if out of order | Find the smallest, swap it into place | Insert the next element into the sorted part |
| After each pass | The largest of the rest is at the right end | The smallest of the rest is at the left end | The sorted part on the left is one longer |
| Passes for n elements | n − 1 | n − 1 | n − 1 |
| Swaps in one pass | Many | At most one | None. Elements are shifted |
| Time complexity | n² | n² | n² |
All three give exactly the same sorted output. They differ only in the route they take.
Worked example: the same list, three routes. For [8, 7, 13, 1, -9, 4], bubble sort made 4 + 3 + 3 + 1 + 0 = 11 swaps, selection sort made 3 swaps, and insertion sort made 1 + 0 + 3 + 4 + 3 = 11 shifts. Selection sort moves data the least. Bubble swaps and insertion shifts match here because both count how many pairs of elements are in the wrong order.
Time complexity
Time complexity tells you how the running time of an algorithm grows as the amount of data grows. For small lists every algorithm feels instant, but for millions of records the choice of algorithm decides whether a program takes seconds or hours. Instead of measuring seconds, which depend on the computer, we look at the structure of the loops.
| Structure of the code | Complexity | Name | Example |
|---|---|---|---|
| No loop | 1 | Constant time | print(a + b) |
| One loop from 1 to n | n | Linear time | Adding up the n items of a list |
| A loop inside a loop | n² | Quadratic time | The three sorts above |
| Nested loop and a separate single loop | n² | Quadratic time | The nested part dominates |
Bubble, selection and insertion sort each contain a loop inside a loop, so all three are quadratic. This is why "which of these three has the best time complexity?" has the answer "all the same, n²".
Worked example: counting comparisons. How does the work grow with n? The nested loops of bubble sort run this many comparisons:
| Code |
|---|
count = 0 |
for i in range(5): |
for j in range(5 - i - 1): |
count = count + 1 |
print(count) |
| Output |
|---|
10 |
For n elements the count is n(n − 1)/2.
| n | Comparisons n(n − 1)/2 | What it shows |
|---|---|---|
| 6 | 15 | Starting point |
| 12 | 66 | n doubled, work is about 4.4 times as much |
| 100 | 4950 | Starting point |
| 200 | 19900 | n doubled, work is about 4 times as much |
Doubling the size of the list makes a quadratic algorithm do roughly four times the work. That is the real meaning of n².
Beyond the textbook. For the exam: all three sorts have time complexity n². In reality: n² is the worst case. Insertion sort on an already sorted list makes only n − 1 comparisons, since every element is compared once with its left neighbour and no shifting happens. Bubble sort can also stop early if a whole pass makes no swap. Still, never answer "insertion sort is faster" in a CUET question unless the data is described as nearly sorted.
Beyond the textbook. For the exam: sorting is done by writing algorithms like those above. In reality: Python already has fast sorting built in. sorted(data) returns a new sorted list and leaves data unchanged, while data.sort() sorts the list in place and returns None. So print(data.sort()) prints None. Both use an algorithm called Timsort, far faster than the quadratic ones for large lists. Pass reverse=True for descending order.
Exam traps
| Trap | Why it tempts | Truth |
|---|---|---|
| Passes and comparisons are the same | Both grow with n | n − 1 passes, but n(n − 1)/2 comparisons in total |
| Selection sort can swap many times per pass | Bubble sort does | At most one swap per pass |
| Insertion sort swaps like bubble sort | Both fix order locally | Insertion sort shifts elements and places temp once |
| Insertion or selection sort has better complexity than bubble sort | They feel more clever | All three are n² |
The bubble sort inner loop runs to n - 1 every time |
It looks simpler | It runs to n - i - 1, because the sorted end is skipped |
| Bubble sort fixes the smallest element first | Sorting "starts" at the small end | Bubble sort fixes the largest element at the right end first; selection fixes the smallest at the left |
| A sort of n elements needs n passes | n elements, n passes | It needs n − 1 passes |
data.sort() returns the sorted list |
It sounds like it produces a result | It sorts in place and returns None; sorted(data) returns the new list |
60-second revision
| Idea | Remember |
|---|---|
| Sorting | Arranging in ascending, descending or alphabetical order |
| Pass | One sweep through the (unsorted part of the) list |
| Bubble sort | Compare and swap neighbours; the largest reaches the end after each pass |
| Selection sort | Find the smallest of the unsorted part, swap it to the left end; at most one swap per pass |
| Insertion sort | Take the next element (temp), shift bigger sorted ones right, place temp |
| Passes | n − 1 for all three |
| Bubble comparisons | n(n − 1)/2 over the whole sort |
| Complexity rules | No loop is 1, one loop is n, nested loop is n² |
| Three sorts | All are n² |
| Why sort | A sorted list is far faster to search |
Where this chapter connects
A sorted list is what makes fast lookup possible, which is the subject of Searching. The list operations that sorting relies on, indexing, swapping and shifting, are the same ones used to build Stack and Queue in Python.
🎯 Practice MCQs
First 3 questions free · create a free account to unlock the rest — answers & explanations included, no payment needed
Q1. Which statement best describes bubble sort?
▸ Show answer & explanation
Answer: C
Bubble sort repeatedly compares neighbours and swaps unordered pairs, which carries the largest element to the end. Option A describes selection sort, option D describes insertion sort, and option B does not describe any of the three algorithms.
Q2. For a list of n = 6 elements, how many passes does bubble sort make?
▸ Show answer & explanation
Answer: B
A list of n elements needs n − 1 passes, which is 5 here. After 5 passes, the one remaining element is automatically in place.
Q3. Statement 1: In each pass of selection sort the smallest element of the unsorted part is swapped with the leftmost element of the unsorted part. Statement 2: Selection sort can make more than one swap in a single pass. Which option is correct?
▸ Show answer & explanation
Answer: D
Selection sort finds the minimum first and then swaps once at most per pass. Several swaps in one pass is a feature of bubble sort.
🔒 12 more practice MCQs
Create a free account to unlock every MCQ in this chapter — answers and explanations included. No payment needed.
Already registered? Just log in and they'll all appear here.
Q4. In insertion sort, what does the variable temp hold at the beginning of each pass?
▸ Show answer & explanation
Answer: A
temp holds the element that is about to be inserted, which is the first element of the unsorted part. The sorted elements larger than temp are shifted right to make space for it.
Q5. Match the algorithm in List I with its key step in List II. List I: (i) Bubble sort (ii) Selection sort (iii) Insertion sort. List II: (p) Insert each unsorted element into its place in the sorted part (q) Find the smallest element of the unsorted part and place it at the front (r) Compare adjacent elements and swap if unordered.
▸ Show answer & explanation
Answer: C
Bubble sort works on adjacent pairs, selection sort picks the minimum, and insertion sort inserts into the sorted part. The other options mix these up.
Q6. Assertion (A): Bubble sort, selection sort and insertion sort all have time complexity n². Reason (R): Each of the three algorithms contains a loop inside a loop.
▸ Show answer & explanation
Answer: A
A nested loop gives quadratic time, and all three programs use nested loops, so R explains A.
Q7. What is the time complexity of an algorithm that has no loop?
▸ Show answer & explanation
Answer: D
Without loops the number of instructions is fixed whatever the amount of data, so the time is constant, written as 1. One loop gives n and a nested loop gives n².
Q8. The list is [8, 7, 13, 1, -9, 4]. After the first complete pass of bubble sort in ascending order, which element is at the last position?
▸ Show answer & explanation
Answer: B
The first pass carries the largest element, 13, to the end. Pass 1 gives [7, 8, 1, -9, 4, 13].
Q9. The time complexity of an algorithm with a single loop running from 1 to n is:
▸ Show answer & explanation
Answer: A
The loop body runs once for each of the n values, so the work grows in step with n. This is linear time.
Q10. After 2 complete passes of bubble sort (ascending) on [5, 1, 4, 2, 8], which two elements are at the end of the list?
▸ Show answer & explanation
Answer: A
Pass 1 gives [1, 4, 2, 5, 8] and pass 2 gives [1, 2, 4, 5, 8]. The last two positions hold 5 and 8, in that order.
Q11. Selection sort (ascending) is applied to [64, 25, 12, 22, 11]. What is the list after the first pass?
▸ Show answer & explanation
Answer: B
The smallest element, 11, is swapped with the first element, 64. Only those two change places. Option C shows what the first pass of bubble sort would give.
Q12. Consider: (1) lst = [4, 2, 1] (2) an outer loop over i in range(len(lst) - 1) containing an inner loop over j in range(len(lst) - i - 1) (3) inside the inner loop, lst[j] and lst[j + 1] are swapped whenever lst[j] > lst[j + 1] (4) print(lst). What is printed?
▸ Show answer & explanation
Answer: D
This is bubble sort. Pass 1 gives [2, 1, 4] and pass 2 gives [1, 2, 4]. Option B is the list after only the first pass.
Q13. Insertion sort is applied to [12, 11, 13, 5, 6]. What does the list look like after 3 passes?
▸ Show answer & explanation
Answer: C
Pass 1 inserts 11 to get [11, 12, 13, 5, 6]. Pass 2 leaves 13 in place. Pass 3 inserts 5 at the front, shifting three elements, to give [5, 11, 12, 13, 6]. Option B is the finished result after pass 4.
Q14. Assertion (A): Selection sort makes at most one swap in each pass. Reason (R): Selection sort swaps adjacent elements whenever they are out of order.
▸ Show answer & explanation
Answer: C
Selection sort scans for the smallest element and then makes one swap, so A is true. Swapping adjacent out of order elements describes bubble sort, so R is false.
Q15. Which sorting algorithm shifts larger elements one place to the right and then places the element once, instead of swapping repeatedly?
▸ Show answer & explanation
Answer: B
Insertion sort shifts the larger sorted elements right to open a gap and writes temp into it once. Bubble sort swaps neighbours repeatedly, and selection sort swaps once per pass.
📊 Previous-Year Questions
Practise with real CUET Computer Science previous-year papers — every question solved, with the correct answer and a step-by-step explanation.
View solved CUET PYQ papers →Ready to drill Computer Science?
Unlock all MCQs, chapter tests, mocks & PYQs for ₹199/year.
Get UniDrill Pro