Current Affairs updated daily
KalviGavaniKalviGavani

Algorithmic Strategies Exercise Solutions | KalviGavani

Complete Samacheer Kalvi Class 12 Computer Science Chapter 4 exercise solutions covering algorithmic strategies, linear search, binary search, bubble sort, selection sort, insertion sort, merge sort, time complexity, and Big O notation with Python implementations.

Updated 13 June 202626 min read

Exercise Solutions Available

Step-by-step answers for all textbook questions in this chapter

View Solutions →

Chapter 4 — Algorithmic Strategies: Exercise Solutions Guide

How to Use This Page

1. Attempt every exercise question on your own first — use your Samacheer Kalvi textbook and class notes. 2. Compare your answers with the solutions below only after you have written your own. 3. Read the explanations for MCQs and True/False items — understanding why an answer is correct is more important than the answer itself. 4. Practise the short and detailed answers by writing them in your own words; do not memorise verbatim. 5. Use the Exam Checklist at the end for a quick pre-exam revision round.


Key Concepts (Quick Recap)

  • An algorithm is a step-by-step procedure for solving a problem in a finite number of steps.
  • Time complexity measures how an algorithm's running time grows with input size; space complexity measures memory usage.
  • Big O notation describes the upper bound (worst-case) growth rate: O(1), O(log n), O(n), O(n log n), O(n²), O(2ⁿ).
  • Linear search checks each element sequentially; time complexity O(n); works on unsorted lists.
  • Binary search halves the search space each step; time complexity O(log n); requires a sorted list.
  • Bubble sort repeatedly swaps adjacent elements if they are in the wrong order; O(n²).
  • Selection sort finds the minimum element and places it at the beginning; O(n²).
  • Insertion sort builds a sorted list by inserting each element into its correct position; O(n²).
  • Merge sort divides the list into halves, sorts each half, and merges them; O(n log n).
  • Best case for sorting (already sorted): bubble sort and insertion sort — O(n); selection sort — O(n²).
  • Stable sort preserves the relative order of equal elements; bubble sort, insertion sort, and merge sort are stable; selection sort is not.

I. Choose the Best Answer (MCQs)

1. What is the time complexity of linear search in the worst case? (a) O(1) (b) O(log n) (c) O(n) (d) O(n²)

Answer(c) O(n) In the worst case, linear search checks every element in the list (the target is at the end or not present). With n elements, it makes n comparisons, giving O(n) time complexity.

2. Binary search requires the list to be: (a) Unsorted (b) Sorted (c) In reverse order (d) Of even length

Answer(b) Sorted Binary search works by comparing the target with the middle element and eliminating half the list each time. This strategy only works if the list is sorted, so the algorithm knows which half to search next.

3. What is the time complexity of binary search? (a) O(n) (b) O(n²) (c) O(log n) (d) O(1)

Answer(c) O(log n) Binary search halves the search space with each comparison. Starting with n elements, after k comparisons, the search space is n/2^k. The maximum number of comparisons is log₂(n), giving O(log n) time complexity.

4. Which sorting algorithm repeatedly finds the minimum element and places it at the beginning? (a) Bubble sort (b) Insertion sort (c) Selection sort (d) Merge sort

Answer(c) Selection sort Selection sort works by finding the smallest element in the unsorted portion and swapping it with the first unsorted element. It repeats this for each position from left to right.

5. What is the worst-case time complexity of bubble sort? (a) O(n) (b) O(log n) (c) O(n log n) (d) O(n²)

Answer(d) O(n²) Bubble sort makes (n-1) passes, and in the worst case (reverse sorted), each pass makes (n-1-i) comparisons. Total comparisons = n(n-1)/2, which is O(n²).

6. Which of the following sorting algorithms has O(n log n) time complexity in all cases? (a) Bubble sort (b) Selection sort (c) Insertion sort (d) Merge sort

Answer(d) Merge sort Merge sort consistently divides the list in half (O(log n) divisions) and merges in O(n) time, giving O(n log n) in all cases — best, average, and worst. Bubble, selection, and insertion sorts all have O(n²) worst case.

7. What is the best-case time complexity of insertion sort? (a) O(n²) (b) O(n) (c) O(log n) (d) O(n log n)

Answer(b) O(n) When the list is already sorted, insertion sort only makes one comparison per element and does not shift any elements. This results in O(n) time for the best case.

8. In bubble sort, after the first pass, which element is guaranteed to be in its correct position? (a) The smallest element (b) The largest element (c) The middle element (d) All elements

Answer(b) The largest element In each pass of bubble sort, adjacent elements are compared and swapped if needed. This "bubbles up" the largest element to the end of the list. After the first pass, the largest element is in its correct position at the end.

9. Which of the following is a divide-and-conquer algorithm? (a) Bubble sort (b) Selection sort (c) Insertion sort (d) Merge sort

Answer(d) Merge sort Merge sort uses divide-and-conquer: it divides the list into halves, recursively sorts each half, and then merges the sorted halves. Bubble, selection, and insertion sorts are comparison-based but not divide-and-conquer.

10. If an algorithm takes 3n² + 5n + 7 operations, what is its Big O complexity? (a) O(3n²) (b) O(5n) (c) O(n²) (d) O(7)

Answer(c) O(n²) Big O notation keeps only the dominant term and drops constants. 3n² + 5n + 7 simplifies to O(n²) because n² grows faster than n or constant terms, and the coefficient 3 is dropped.

II. Fill in the Blanks

1. The time complexity of linear search in the worst case is O(n).

2. Binary search works only on a sorted list.

3. The time complexity of binary search is O(log n).

4. In selection sort, the minimum element is found and placed at the beginning in each pass.

5. The best-case time complexity of bubble sort is O(n) (when the list is already sorted with an optimised version).

6. Merge sort uses the divide-and-conquer strategy.

7. The worst-case time complexity of merge sort is O(n log n).

8. In bubble sort, adjacent elements are compared and swapped if they are in the wrong order.

9. Big O notation describes the worst-case (upper bound) time complexity of an algorithm.

10. An algorithm with O(1) time complexity means the running time is constant regardless of input size.


III. True or False

1. Linear search is more efficient than binary search for large sorted lists. False. Binary search has O(log n) complexity, which is much faster than linear search's O(n) for large sorted lists. Linear search is only preferred for small or unsorted lists.

2. Binary search can be applied to an unsorted list. False. Binary search requires the list to be sorted. On an unsorted list, halving the search space does not guarantee the target is in either half. It would give incorrect results.

3. Bubble sort is a stable sorting algorithm. True. Bubble sort only swaps adjacent elements when they are strictly out of order (i.e., when the left element is greater). Equal elements are not swapped, so their relative order is preserved.

4. The time complexity of selection sort is O(n²) in all cases (best, average, worst). True. Selection sort always performs n(n-1)/2 comparisons regardless of whether the list is already sorted, because it scans the entire unsorted portion for the minimum in every pass.

5. Merge sort requires additional memory for merging. True. Merge sort requires O(n) additional space for the temporary arrays used during the merge step. This is a trade-off for its O(n log n) time complexity.

6. Insertion sort is efficient for large datasets. False. Insertion sort has O(n²) worst-case and average-case time complexity, making it inefficient for large datasets. It is efficient for small or nearly sorted datasets where it performs close to O(n).

7. Binary search compares the target with the middle element and eliminates half the list. True. Binary search compares the target with the middle element. If the target is smaller, the right half is eliminated. If the target is larger, the left half is eliminated. This is why it achieves O(log n) complexity.

8. The best-case time complexity of bubble sort is O(n²). False. With an optimised bubble sort (that stops early if no swaps occur in a pass), the best-case time complexity is O(n) when the list is already sorted. Without optimisation, it is O(n²).

9. Space complexity of merge sort is O(1). False. Merge sort has a space complexity of O(n) because it requires additional temporary arrays for the merging step. Only O(1) space algorithms use constant extra memory.

10. Big O notation focuses on the dominant term and ignores constants and lower-order terms. True. Big O notation keeps only the highest-order term and drops constants. For example, 3n² + 5n + 7 becomes O(n²), and 2n log n + 10n becomes O(n log n).


IV. Match the Following

Set A

AB
1. Linear searchc. O(n) time complexity
2. Binary searche. O(log n) time complexity
3. Bubble sorta. Adjacent element comparison and swap
4. Selection sortd. Finds minimum and places at beginning
5. Merge sortb. Divide-and-conquer with O(n log n)

Set B

AB
1. O(1)d. Constant time
2. O(log n)a. Logarithmic time
3. O(n)e. Linear time
4. O(n log n)c. Linearithmic time
5. O(n²)b. Quadratic time

V. Short Answer Questions

1. What is linear search? Write a Python function and explain its time complexity.
Answer

Linear search checks each element in the list one by one from the beginning until the target is found or the list ends.

def linear_search(arr, target):
    for i in range(len(arr)):
        if arr[i] == target:
            return i    # Found: return index
    return -1           # Not found

# Example
numbers = [34, 12, 56, 78, 23, 9]
print(linear_search(numbers, 56))  # 2 (found at index 2)
print(linear_search(numbers, 99))  # -1 (not found)

Time complexity:

  • Best case: O(1) — target is at the first position.
  • Worst case: O(n) — target is at the last position or not present.
  • Average case: O(n) — target is somewhere in the middle.

Linear search works on both sorted and unsorted lists but is slow for large datasets.


2. What is binary search? Write a Python function and explain why it is faster than linear search.
Answer

Binary search works on a sorted list by repeatedly dividing the search interval in half. It compares the target with the middle element and eliminates half the list each time.

def binary_search(arr, target):
    low = 0
    high = len(arr) - 1

    while low <= high:
        mid = (low + high) // 2

        if arr[mid] == target:
            return mid           # Found: return index
        elif arr[mid] < target:
            low = mid + 1        # Search right half
        else:
            high = mid - 1       # Search left half

    return -1  # Not found

# Example (list must be sorted)
numbers = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
print(binary_search(numbers, 23))  # 5
print(binary_search(numbers, 7))   # -1

Why binary search is faster:

  • Linear search checks n elements in the worst case.
  • Binary search checks at most log₂(n) elements.
  • For 1,000,000 elements: linear search may need 1,000,000 comparisons; binary search needs at most 20 comparisons.
List size (n)Linear search (O(n))Binary search (O(log n))
1001007
1,0001,00010
1,000,0001,000,00020

Prerequisite: The list must be sorted before binary search can be applied.


3. Explain bubble sort with a Python function. Trace through an example.
Answer

Bubble sort repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the wrong order. After each pass, the largest unsorted element "bubbles up" to its correct position.

def bubble_sort(arr):
    n = len(arr)
    for i in range(n - 1):
        swapped = False
        for j in range(n - 1 - i):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
        if not swapped:  # Optimisation: stop if no swaps
            break
    return arr

Trace through: [5, 3, 8, 1]

Pass 1:

  • Compare 5, 3 → swap → [3, 5, 8, 1]
  • Compare 5, 8 → no swap → [3, 5, 8, 1]
  • Compare 8, 1 → swap → [3, 5, 1, 8] (8 is in correct position)

Pass 2:

  • Compare 3, 5 → no swap → [3, 5, 1, 8]
  • Compare 5, 1 → swap → [3, 1, 5, 8] (5 is in correct position)

Pass 3:

  • Compare 3, 1 → swap → [1, 3, 5, 8] (3 is in correct position)
Result[1, 3, 5, 8]

Time complexity:

  • Best case: O(n) — already sorted (with optimisation, one pass with no swaps).
  • Worst case: O(n²) — reverse sorted.
  • Average case: O(n²).

4. Explain selection sort with a Python function. Trace through an example.
Answer

Selection sort divides the list into sorted and unsorted portions. In each pass, it finds the minimum element in the unsorted portion and swaps it with the first unsorted element.

def selection_sort(arr):
    n = len(arr)
    for i in range(n - 1):
        min_idx = i
        for j in range(i + 1, n):
            if arr[j] < arr[min_idx]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr

Trace through: [64, 25, 12, 22, 11]

Pass 1: Find min in [64, 25, 12, 22, 11] → 11 at index 4. Swap with index 0 → [11, 25, 12, 22, 64]

Pass 2: Find min in [25, 12, 22, 64] → 12 at index 2. Swap with index 1 → [11, 12, 25, 22, 64]

Pass 3: Find min in [25, 22, 64] → 22 at index 3. Swap with index 2 → [11, 12, 22, 25, 64]

Pass 4: Find min in [25, 64] → 25 at index 3. No swap needed → [11, 12, 22, 25, 64]

Result[11, 12, 22, 25, 64]

Time complexity: O(n²) in all cases (best, average, worst), because it always scans the entire unsorted portion.


5. Explain insertion sort with a Python function. What is its best-case time complexity and when does it occur?
Answer

Insertion sort builds a sorted list by taking each element and inserting it into its correct position in the already-sorted portion.

def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key
    return arr

# Example
numbers = [12, 11, 13, 5, 6]
print(insertion_sort(numbers))  # [5, 6, 11, 12, 13]

Trace through: [12, 11, 13, 5]

  • i=1: key=11, shift 12 right → [12, 12, 13, 5], insert 11 → [11, 12, 13, 5]
  • i=2: key=13, no shifts needed → [11, 12, 13, 5]
  • i=3: key=5, shift 13, 12, 11 right → [11, 11, 12, 13], insert 5 → [5, 11, 12, 13]

Best-case time complexity: O(n) This occurs when the list is already sorted. Each element only needs one comparison (no shifting), so the inner while loop runs zero times per element.

Worst-case time complexity: O(n²) This occurs when the list is reverse sorted. Each new element must be compared with all previous elements and shifted to the beginning.


6. What is Big O notation? Give examples for O(1), O(n), O(log n), O(n²), and O(n log n).
Answer

Big O notation describes the upper bound (worst-case) time complexity of an algorithm as a function of input size n. It focuses on the dominant term and ignores constants and lower-order terms.

Big ONameExample
O(1)ConstantAccessing an array element by index: arr[5]
O(log n)LogarithmicBinary search — halves the search space each step
O(n)LinearLinear search — checks each element once
O(n log n)LinearithmicMerge sort — divides and merges
O(n²)QuadraticBubble sort, selection sort — nested loops

Examples:

  • O(1): arr[0] — accessing any element by index takes constant time regardless of array size.
  • O(log n): Binary search on 1,000,000 elements needs at most 20 comparisons.
  • O(n): Linear search on 1,000 elements needs at most 1,000 comparisons.
  • O(n²): Bubble sort on 100 elements needs up to 100×99/2 = 4,950 comparisons.
  • O(n log n): Merge sort on 1,000 elements needs about 1,000 × 10 = 10,000 operations.

Simplification rule: 3n² + 5n + 7 → O(n²) (keep dominant term, drop constants).


VI. Detailed Answer Questions

1. Explain binary search algorithm in detail with Python implementation. Trace through an example and compare it with linear search.
Answer

Binary search is an efficient algorithm for finding an element in a sorted list. It works by repeatedly dividing the search interval in half.

Algorithm: 1. Set low = 0 and high = len(arr) - 1. 2. While low <= high: a. Calculate mid = (low + high) // 2. b. If arr[mid] == target, return mid (found). c. If arr[mid] < target, set low = mid + 1 (search right half). d. If arr[mid] > target, set high = mid - 1 (search left half). 3. If the loop ends, return -1 (not found).

Python implementation:

def binary_search(arr, target):
    low = 0
    high = len(arr) - 1

    while low <= high:
        mid = (low + high) // 2

        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return -1

# Example
numbers = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
print(binary_search(numbers, 23))  # 5
print(binary_search(numbers, 72))  # 8
print(binary_search(numbers, 7))   # -1

Trace: searching for 23 in [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]

Steplowhighmidarr[mid]ComparisonAction
10941623 > 16low = 5
25975623 < 56high = 6
35652323 == 23Found at index 5

Only 3 comparisons for a list of 10 elements!

Comparison: Linear search vs Binary search

FeatureLinear SearchBinary Search
PrerequisiteWorks on any listRequires sorted list
Best caseO(1)O(1)
Worst caseO(n)O(log n)
Average caseO(n)O(log n)
For n=1,000,000Up to 1,000,000 comparisonsUp to 20 comparisons
ImplementationSimpleSlightly more complex
Use caseSmall or unsorted listsLarge sorted lists

2. Explain merge sort algorithm in detail with Python implementation. Trace through an example and discuss its time and space complexity.
Answer

Merge sort is a divide-and-conquer algorithm that recursively splits the list into halves, sorts each half, and then merges the sorted halves.

Algorithm: 1. Divide: Split the list into two halves. 2. Conquer: Recursively sort each half. 3. Merge: Combine the two sorted halves into a single sorted list.

Python implementation:

def merge_sort(arr):
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0

    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    result.extend(left[i:])
    result.extend(right[j:])
    return result

# Example
numbers = [38, 27, 43, 3, 9, 82, 10]
print(merge_sort(numbers))  # [3, 9, 10, 27, 38, 43, 82]

Trace: [38, 27, 43, 3, 9, 82, 10]

[38, 27, 43, 3, 9, 82, 10] / \ [38, 27, 43] [3, 9, 82, 10] / \ / \ [38] [27, 43] [3, 9] [82, 10] / \ / \ / \ [27] [43] [3] [9] [82] [10] Merging: [27] + [43] → [27, 43] [3] + [9] → [3, 9] [82] + [10] → [10, 82] [38] + [27, 43] → [27, 38, 43] [3, 9] + [10, 82] → [3, 9, 10, 82] [27, 38, 43] + [3, 9, 10, 82] → [3, 9, 10, 27, 38, 43, 82]

Time complexity:

  • Best case: O(n log n)
  • Average case: O(n log n)
  • Worst case: O(n log n)

Merge sort always divides the list into halves (log n levels) and merges n elements at each level, so the time complexity is consistently O(n log n).

Space complexity: O(n) — requires temporary arrays for merging.

Advantages:

  • Consistent O(n log n) performance regardless of input.
  • Stable sort (preserves order of equal elements).
  • Suitable for large datasets and linked lists.

Disadvantages:

  • Requires O(n) extra memory.
  • Slower than insertion sort for very small lists.

3. Compare bubble sort, selection sort, and insertion sort with their algorithms, time complexities, and examples.
Answer
FeatureBubble SortSelection SortInsertion Sort
StrategySwap adjacent elementsFind min, place at beginningInsert element into sorted portion
Best caseO(n) (already sorted)O(n²)O(n) (already sorted)
Average caseO(n²)O(n²)O(n²)
Worst caseO(n²)O(n²)O(n²) (reverse sorted)
SpaceO(1)O(1)O(1)
Stable?YesNoYes
Adaptive?Yes (stops early)NoYes
Swaps per passManyOne (min swap)Shifts elements

Bubble Sort — Python implementation:

def bubble_sort(arr):
    n = len(arr)
    for i in range(n - 1):
        swapped = False
        for j in range(n - 1 - i):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
        if not swapped:
            break
    return arr

print(bubble_sort([5, 1, 4, 2, 8]))  # [1, 2, 4, 5, 8]

Selection Sort — Python implementation:

def selection_sort(arr):
    n = len(arr)
    for i in range(n - 1):
        min_idx = i
        for j in range(i + 1, n):
            if arr[j] < arr[min_idx]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr

print(selection_sort([5, 1, 4, 2, 8]))  # [1, 2, 4, 5, 8]

Insertion Sort — Python implementation:

def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key
    return arr

print(insertion_sort([5, 1, 4, 2, 8]))  # [1, 2, 4, 5, 8]

When to use which:

  • Bubble sort: Educational purposes; rarely used in practice.
  • Selection sort: When memory writes are costly (minimum swaps); small datasets.
  • Insertion sort: Nearly sorted data; small datasets; as part of more advanced algorithms (like Timsort).

4. Explain Big O notation with examples. How do you determine the time complexity of an algorithm?
Answer

Big O notation describes the upper bound (worst-case) growth rate of an algorithm's time or space requirements as a function of input size n. It focuses on the dominant term and ignores constants and lower-order terms.

Rules for determining Big O:

1. Drop constants: O(3n) → O(n); O(2n²) → O(n²) 2. Drop lower-order terms: O(n² + n) → O(n²); O(n log n + n) → O(n log n) 3. Keep the dominant term: For large n, n² dominates n, which dominates log n, which dominates 1.

Common Big O categories (from fastest to slowest):

Big ONameGrowthExample
O(1)ConstantNo growthAccessing array by index
O(log n)LogarithmicVery slow growthBinary search
O(√n)Square rootModerate growthChecking if n is prime
O(n)LinearProportional to nLinear search
O(n log n)Linearithmicn × log nMerge sort
O(n²)Quadraticn × nBubble sort
O(2ⁿ)ExponentialDoubles with each nRecursive Fibonacci
O(n!)FactorialExtremely fast growthTravelling salesman (brute force)

Determining time complexity from code:

Example 1 — Single loop: O(n)

def print_items(n):
    for i in range(n):       # Runs n times
        print(i)
# Time complexity: O(n)

Example 2 — Nested loop: O(n²)

def print_pairs(n):
    for i in range(n):          # Runs n times
        for j in range(n):      # Runs n times for each i
            print(i, j)
# Time complexity: O(n × n) = O(n²)

Example 3 — Halving loop: O(log n)

def halve(n):
    while n > 1:
        n = n // 2    # Halves n each step
        print(n)
# Time complexity: O(log n)

Example 4 — Sequential statements: O(n²)

def combined(n):
    for i in range(n):       # O(n)
        print(i)
    for i in range(n):       # O(n²)
        for j in range(n):
            print(i, j)
# Time complexity: O(n) + O(n²) = O(n²)
# Drop the lower-order term O(n)

Example 5 — Binary search: O(log n)

def binary_search(arr, target):
    low, high = 0, len(arr) - 1
    while low <= high:           # Halves search space each step
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1
# Time complexity: O(log n) — search space halves each iteration

5. Explain merge sort with a step-by-step trace. Compare merge sort with bubble sort in terms of time and space complexity.
Answer

Merge sort is a divide-and-conquer sorting algorithm that: 1. Divides the list into two halves. 2. Recursively sorts each half. 3. Merges the two sorted halves.

Step-by-step trace: sorting [6, 5, 3, 1, 8, 7, 2, 4]

Divide phase: [6, 5, 3, 1, 8, 7, 2, 4] ↓ split [6, 5, 3, 1] [8, 7, 2, 4] ↓ split ↓ split [6, 5] [3, 1] [8, 7] [2, 4] ↓ split ↓ split ↓ split ↓ split [6] [5] [3] [1] [8] [7] [2] [4] Merge phase: [6] [5] → [5, 6] [3] [1] → [1, 3] [8] [7] → [7, 8] [2] [4] → [2, 4] [5, 6] [1, 3] → [1, 3, 5, 6] [7, 8] [2, 4] → [2, 4, 7, 8] [1, 3, 5, 6] [2, 4, 7, 8] → [1, 2, 3, 4, 5, 6, 7, 8]

Merge step detail: merging [1, 3, 5, 6] and [2, 4, 7, 8]

left = [1, 3, 5, 6], right = [2, 4, 7, 8] Compare 1, 2 → 1 is smaller → result = [1] Compare 3, 2 → 2 is smaller → result = [1, 2] Compare 3, 4 → 3 is smaller → result = [1, 2, 3] Compare 5, 4 → 4 is smaller → result = [1, 2, 3, 4] Compare 5, 7 → 5 is smaller → result = [1, 2, 3, 4, 5] Compare 6, 7 → 6 is smaller → result = [1, 2, 3, 4, 5, 6] Append remaining right: result = [1, 2, 3, 4, 5, 6, 7, 8]

Comparison: Merge Sort vs Bubble Sort

FeatureMerge SortBubble Sort
StrategyDivide and conquerSwap adjacent elements
Best caseO(n log n)O(n) (optimised)
Average caseO(n log n)O(n²)
Worst caseO(n log n)O(n²)
Space complexityO(n)O(1)
Stable?YesYes
Adaptive?NoYes
Practical useLarge datasets, external sortingEducational, small datasets
For n=10,000~140,000 operations~50,000,000 operations

Merge sort is significantly faster for large datasets (O(n log n) vs O(n²)), but requires extra O(n) memory. Bubble sort is simple but impractical for large lists.


Common Mistakes

1. Applying binary search to an unsorted list: Binary search only works on sorted lists. On an unsorted list, halving the search space is meaningless and produces incorrect results.

2. Confusing best-case and worst-case complexities: Bubble sort is O(n) best case (already sorted) but O(n²) worst case. Selection sort is O(n²) in all cases. Always specify which case you are analysing.

3. Forgetting that merge sort needs extra space: Merge sort requires O(n) additional memory for temporary arrays. This is a trade-off for its O(n log n) speed.

4. Confusing selection sort with insertion sort: Selection sort finds the minimum and swaps; insertion sort takes each element and inserts it into the sorted portion. They have different best-case behaviours.

5. Counting passes instead of comparisons: Bubble sort makes approximately n²/2 comparisons, not n passes. Remember that each pass makes fewer comparisons (n-1, n-2, ..., 1).

6. Dropping the wrong term in Big O: O(n² + n) simplifies to O(n²), not O(n). The highest-order term dominates for large n. Similarly, O(n log n + n) = O(n log n).

7. Assuming all O(n²) sorts are equally slow: Insertion sort can be O(n) on nearly sorted data, making it practical for small or nearly sorted lists. Selection sort is always O(n²) regardless of input.


Exam Checklist

  • [ ] Can define linear search and trace through it with O(n) complexity
  • [ ] Can define binary search and trace through it with O(log n) complexity
  • [ ] Know that binary search requires a sorted list
  • [ ] Can implement bubble sort and trace through an example
  • [ ] Can implement selection sort and trace through an example
  • [ ] Can implement insertion sort and trace through an example
  • [ ] Can implement merge sort and trace through an example
  • [ ] Can compare time and space complexities of all sorting algorithms
  • [ ] Can explain Big O notation and simplify expressions (drop constants and lower-order terms)
  • [ ] Can determine time complexity from code (single loop, nested loop, halving loop)

Frequently Asked Questions

The time complexity of binary search is O(log n). It repeatedly halves the search space, so the maximum number of comparisons is log₂(n). However, binary search requires the list to be sorted beforehand.