IT235 Discrete Structure

Discrete StructureUnit 812 min read

Sorting Algorithms & Complexity: Big-O, Bubble, Insertion, Merge, Quick

Unit 8 of Discrete Structure covers fundamental sorting algorithms (Bubble, Insertion, Merge, Quick), their time/space complexity analysis using Big-O/Ω/Θ notation, and real-world applications in databases, search engines, and transaction systems. Learn how to trace algorithms, compare efficiencies, and apply asymptoti

TAKEAWAYS:

  • Sorting algorithms rearrange data into ascending/descending order; Bubble/Insertion are simple but slow (), while Merge/Quick are efficient () for large datasets.
  • Big-O/Ω/Θ classify algorithm performance: means quadratic time growth, while is logarithmic—critical for scaling systems like NEPSE stock data or NTC call routing.
  • Divide-and-conquer (Merge/Quick) splits problems into subproblems (e.g., QuickSort’s pivot selection), reducing complexity exponentially compared to linear scans.
  • Stability matters: Insertion/Bubble sorts preserve order of equal keys (useful for sorting Nepali names by first name then last name), while QuickSort may not.
  • Real-world ties: Banks use MergeSort for transaction logs (stable, predictable ), while Pathao’s ride-matching uses priority queues (underpinned by sorting) to assign nearest drivers.
  • Exam focus: Trace algorithms step-by-step (e.g., BubbleSort swaps), derive time complexity from loops, and compare methods using asymptotic tables.

1. Why Sorting Matters: Definitions and Goals

Sorting is the process of arranging data in a specific order (ascending/descending). It’s a fundamental operation in computer science because:

  • Efficient searching: Binary search () only works on sorted data.
  • Data compression: Algorithms like Huffman coding rely on sorted frequencies.
  • Real-time systems: Airlines sort flights by departure time; eSewa sorts transactions by timestamp.
012345678910Key=3 (equal)Key=7 (equal)Key=1 (smaller)Key=5 (larger)
Stable sort example: Original order of equal keys (3,7) preserved

Key terms:

  • Key: The field used for comparison (e.g., price in Daraz orders).
  • Stable sort: Preserves relative order of equal keys (e.g., sorting students by grade then name).
  • In-place: Uses constant extra space (e.g., QuickSort vs. MergeSort’s ).

classDiagram
    class SortingAlgorithm {
        +sort(data: List) List
        +timeComplexity() String
        +spaceComplexity() String
        +isStable() Boolean
    }
    class BubbleSort {
        +sort() O(n²)
        +isStable() true
    }
    class InsertionSort {
        +sort() O(n²)
        +isStable() true
    }
    class MergeSort {
        +sort() O(n log n)
        +isStable() true
    }
    class QuickSort {
        +sort() O(n log n) avg
        +isStable() false
    }
    SortingAlgorithm <|-- BubbleSort
    SortingAlgorithm <|-- InsertionSort
    SortingAlgorithm <|-- MergeSort
    SortingAlgorithm <|-- QuickSort

2. In the Real World

  • eSewa/Khalti: Use MergeSort to sort transactions by timestamp before processing payments. Stability ensures chronological order for refunds.
  • Daraz: Applies QuickSort to sort products by price or rating for search results. Pivot selection (e.g., median-of-three) speeds up sorting for millions of items.
  • NTC Call Routing: Uses priority queues (underpinned by sorting) to route emergency calls (highest priority first) faster than routine calls.
  • Nepal Rastra Bank: Sorts loan applications by risk_score (ascending) to prioritize low-risk borrowers. InsertionSort works for small batches (<1000), while MergeSort handles annual reports.

Worked Example: Daraz Order Processing Problem: Daraz has 5 pending orders with order_id and priority (1=highest). Sort by priority using BubbleSort.

Order ID | Priority
---------|----------
O101     | 3
O102     | 1
O103     | 5
O104     | 2
O105     | 4

Trace:

  1. Compare O101 (3) and O102 (1) → swap → O102, O101, O103, O104, O105.
  2. Compare O101 (3) and O103 (5) → no swap.
  3. Repeat until no swaps in a pass. Final Sorted Order:
O102 (1), O104 (2), O101 (3), O105 (4), O103 (5)

3. Sorting Algorithms: How They Work

A. BubbleSort: The "Bubbling Up" Method

How it works:

  • Repeatedly steps through the list, compares adjacent elements, and swaps them if in the wrong order.
  • The largest unsorted element "bubbles up" to its correct position in each pass.

Visual Trace for [30, 20, 11, 45, 10]:

300201112453104
BubbleSort Pass 1: Largest element (45) bubbles to end

Time Complexity:

  • Worst/Average: (nested loops).
  • Best: (if already sorted, with optimized early termination).

When to Use:

  • Small datasets (<100 elements).
  • Nearly sorted data (few swaps needed).

Disadvantages:

  • Inefficient for large (e.g., sorting 1M NEPSE stock records).

B. InsertionSort: Building a Sorted Subarray

How it works:

  • Divides the list into a sorted and unsorted subarray.
  • Takes each element from the unsorted subarray and inserts it into the correct position in the sorted subarray.

Trace for [12, 5, 7, 18, 10]:

1205172183104
InsertionSort: Building sorted subarray step-by-step

Time Complexity:

  • Worst/Average: .
  • Best: (already sorted).

Advantages:

  • Stable, in-place, and efficient for small or nearly sorted data.
  • Used in Python’s list.sort() for small subarrays.

Real-World Use:

  • Online transaction processing: Inserting new payments into a sorted ledger (e.g., Khalti’s daily transactions).

C. MergeSort: Divide and Conquer

How it works:

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

Visual for [30, 20, 11, 45, 10]:

flowchart TD
    A["MergeSort([30,20,11,45,10])"] --> B["Left=[30,20,11], Right=[45,10]"]
    B --> C["MergeSort([30,20,11])"] --> D["Left=[30,20], Right=[11]"]
    D --> E["MergeSort([30,20])"] --> F["Left=[30], Right=[20]"]
    F --> G["Merge([30],[20])"] --> H["20,30"]
    H --> I["Merge([20,30],[11])"] --> J["11,20,30"]
    J --> K["MergeSort([45,10])"] --> L["Left=[45], Right=[10]"]
    L --> M["Merge([45],[10])"] --> N["10,45"]
    N --> O["Merge([11,20,30],[10,45])"] --> P["10,11,20,30,45"]

Time Complexity:

  • All cases: (divide: , merge: ).

Space Complexity: (requires auxiliary space for merging).

Advantages:

  • Stable and predictable performance.
  • Used in external sorting (e.g., sorting large datasets on disk, like NTC’s call logs).

Disadvantages:

  • Not in-place (uses extra memory).

D. QuickSort: The Fastest in Practice

How it works:

  1. Choose a pivot (e.g., last element).
  2. Partition: Rearrange elements so all < pivot are left, all > pivot are right.
  3. Recurse: Apply QuickSort to the left and right partitions.

Trace for [30, 20, 11, 45, 10] (pivot=10):

300201112453104
QuickSort: Partitioning and recursion with pivot=10

Time Complexity:

  • Average: .
  • Worst: (if pivot is smallest/largest element; e.g., already sorted list).

Space Complexity: (stack space for recursion).

Optimizations:

  • Randomized pivot: Avoid worst-case scenarios.
  • Hybrid approach: Use InsertionSort for small subarrays (e.g., ).

Real-World Use:

  • Google’s sorting libraries use a tuned QuickSort variant.
  • Pathao’s driver assignment: QuickSort prioritizes drivers closest to pickup locations.

4. Complexity Analysis: Big-O, Ω, and Θ

Why It Matters:

  • Big-O: Upper bound (worst-case). "This algorithm will never be slower than ."
  • Big-Ω: Lower bound (best-case). "This algorithm will always take at least ."
  • Big-Θ: Tight bound (exact growth). "This algorithm always runs in ."
102030405060708090100200040006000800010000xO(n²) (BubbleSort)O(n log n) (MergeSort)O(n) (Best case)
Growth rates of sorting algorithms' time complexity

Comparison Table:

Algorithm Best Case Average Case Worst Case Space Complexity Stable?
BubbleSort Yes
InsertionSort Yes
MergeSort Yes
QuickSort No

Worked Example: Analyzing Nested Loops

for i in range(n):          # O(n)
    for j in range(n):      # O(n)
        print(i, j)

Complexity: because the inner loop runs times for each of the outer iterations.

Exam Tip: Count the number of operations in the innermost loop and multiply by the number of times it executes.


5. Choosing the Right Sort

Decision Factors:

  1. Data Size:
    • Small (): InsertionSort/BubbleSort.
    • Large (): MergeSort/QuickSort.
  2. Stability Needed:
    • Stable sort (e.g., MergeSort) for multi-key sorting (e.g., sorting Nepali names by last_name then first_name).
  3. Memory Constraints:
    • In-place sorts (QuickSort) for embedded systems (e.g., traffic light controllers).
  4. Data Characteristics:
    • Nearly sorted: InsertionSort.
    • Random data: QuickSort (fastest average case).

Example Scenario:

  • Task: Sort 10,000 NEPSE stock trades by timestamp.
  • Choice: MergeSort (stable, ) to ensure chronological order for audits.

6. Exam Tip: How to Score Full Marks

  1. Tracing Algorithms:

    • Show every swap/comparison in BubbleSort/InsertionSort.
    • For QuickSort, explicitly state the pivot, partition index, and recursive calls.
    • Example: For [30, 20, 11, 45, 10] in BubbleSort, write out each pass until sorted.
  2. Complexity Derivation:

    • Identify nested loops and their bounds.
    • Ignore constants and lower-order terms (e.g., → ).
    • Example: For a triple-nested loop, write .
  3. Comparisons:

    • Use a table to compare algorithms (like above).
    • Highlight trade-offs (e.g., "MergeSort is stable but uses space").
  4. Real-World Applications:

    • Link algorithms to Nepali contexts:
      • "BubbleSort could sort a small class’s exam scores by percentage."
      • "QuickSort is used in Daraz’s search to rank products by price or rating."
    • Avoid vague answers like "it’s used in databases." Specify how.
  5. Common Pitfalls:

    • Forgetting to count the number of comparisons/swaps in traces.
    • Misidentifying stable vs. unstable sorts (e.g., calling QuickSort stable).
    • Confusing Big-O with exact runtime (e.g., saying BubbleSort is "faster" than MergeSort for without context).

Final Visual Summary:

Key Takeaway for Exams:

"If the question asks to sort data, trace the algorithm step-by-step. If it asks to analyze, derive the complexity from loops and compare methods. Always tie back to real-world examples like eSewa, Daraz, or NTC."

Based on the TU BITM syllabus for Discrete Structure (IT235), unit 8.

Discussion

Loading…