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.
Key terms:
- Key: The field used for comparison (e.g.,
pricein Daraz orders). - Stable sort: Preserves relative order of equal keys (e.g., sorting students by
gradethenname). - 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 <|-- QuickSort2. In the Real World
- eSewa/Khalti: Use MergeSort to sort transactions by
timestampbefore processing payments. Stability ensures chronological order for refunds. - Daraz: Applies QuickSort to sort products by
priceorratingfor 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:
- Compare O101 (3) and O102 (1) → swap → O102, O101, O103, O104, O105.
- Compare O101 (3) and O103 (5) → no swap.
- 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]:
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]:
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:
- Divide: Split the list into two halves.
- Conquer: Recursively sort each half.
- 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:
- Choose a pivot (e.g., last element).
- Partition: Rearrange elements so all < pivot are left, all > pivot are right.
- Recurse: Apply QuickSort to the left and right partitions.
Trace for [30, 20, 11, 45, 10] (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 ."
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:
- Data Size:
- Small (): InsertionSort/BubbleSort.
- Large (): MergeSort/QuickSort.
- Stability Needed:
- Stable sort (e.g., MergeSort) for multi-key sorting (e.g., sorting Nepali names by
last_namethenfirst_name).
- Stable sort (e.g., MergeSort) for multi-key sorting (e.g., sorting Nepali names by
- Memory Constraints:
- In-place sorts (QuickSort) for embedded systems (e.g., traffic light controllers).
- 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
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.
Complexity Derivation:
- Identify nested loops and their bounds.
- Ignore constants and lower-order terms (e.g., → ).
- Example: For a triple-nested loop, write .
Comparisons:
- Use a table to compare algorithms (like above).
- Highlight trade-offs (e.g., "MergeSort is stable but uses space").
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
priceorrating."
- "BubbleSort could sort a small class’s exam scores by
- Avoid vague answers like "it’s used in databases." Specify how.
- Link algorithms to Nepali contexts:
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…