Skip to the content.

Big O and Algorithmic Efficiency

Popcorn Hack 1

You need to check if a number is even or odd. Which TWO strategies are the most efficient?

  • Check if the last digit is 0, 2, 4, 6, or 8 manually
    This is efficient because there are only 5 checks, which are pretty easy.

  • Use the modulus operator (%) to check if the remainder when divided by 2 is 0
    This is efficient because it is quick for a program to check and doesn’t depend on input size.


Popcorn Hack 2

What is the time complexity of each algorithm?

  • Linear Search: O(n)
  • Binary Search: O(log n)
  • log₂(10,000,000) = 23
  • Binary search can be up to ~434,783 times faster than linear search in theory.

What happens if you increase data_size to 20,000,000?

  • Linear Search: Time roughly doubles
  • Binary Search: Time increases slightly, but much less than linear search

Homework hack 1:

 ``` import random
import time

# Generate a list of 100 random integers between 1 and 1000
original_list = [random.randint(1, 1000) for _ in range(100)]

# Bubble Sort
def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]

# Merge Sort
def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2
        left = arr[:mid]
        right = arr[mid:]

        merge_sort(left)
        merge_sort(right)

        i = j = k = 0
        while i < len(left) and j < len(right):
            if left[i] < right[j]:
                arr[k] = left[i]
                i += 1
            else:
                arr[k] = right[j]
                j += 1
            k += 1

        while i < len(left):
            arr[k] = left[i]
            i += 1
            k += 1

        while j < len(right):
            arr[k] = right[j]
            j += 1
            k += 1

# Make copies so each sort gets the same input
bubble_list = original_list.copy()
merge_list = original_list.copy()

# Time Bubble Sort
start_time = time.time()
bubble_sort(bubble_list)
bubble_duration = time.time() - start_time

# Time Merge Sort
start_time = time.time()
merge_sort(merge_list)
merge_duration = time.time() - start_time

# Output Results
print(f"Bubble Sort Time: {bubble_duration:.6f} seconds")
print(f"Merge Sort Time: {merge_duration:.6f} seconds")

# Determine which is faster
if bubble_duration < merge_duration:
    print("Bubble Sort is faster.")
else:
    print("Merge Sort is faster.")

 ``` 

Output

``` 
 Bubble Sort Time: 0.003212 seconds
Merge Sort Time: 0.000312 seconds
Merge Sort is faster.

Final question/ reflection
Why does Merge Sort consistently outperform Bubble Sort?
Merge Sort has a time complexity of O(n log n), while Bubble Sort is O(n²).
This means Merge Sort scales much better as input size increases, making it significantly faster for large or even moderately sized datasets.
```

Homework hack 2

```import random

# Generate a sorted list from 1 to 100,000
data = list(range(1, 100001))

# Pick a random target from the list
target = random.choice(data)

# Linear Search with comparison count
def linear_search(arr, target):
    count = 0
    for i in range(len(arr)):
        count += 1
        if arr[i] == target:
            return count
    return -1

# Binary Search with comparison count
def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    count = 0
    while left <= right:
        count += 1
        mid = (left + right) // 2
        if arr[mid] == target:
            return count
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1

# Run both searches
linear_comparisons = linear_search(data, target)
binary_comparisons = binary_search(data, target)

# Output results
print(f"Target: {target}")
print(f"Linear Search Comparisons: {linear_comparisons}")
print(f"Binary Search Comparisons: {binary_comparisons}")

```

Output:

 ```Target: 74528
Linear Search Comparisons: 74528
Binary Search Comparisons: 17

Which search algorithm is faster, and why?
Binary Search is faster because it uses a divide-and-conquer strategy with O(log n) complexity,
while Linear Search checks each element one-by-one with O(n) complexity.

What happens if you run both searches on an unsorted list?
Linear Search still works because it doesn’t rely on order.
Binary Search will give incorrect results or fail because it requires the list to be sorted.
```