Core Concepts | .9 | .11 | .12 | .13 | .14 | .15 | .16 | .17 | .18 |
3.17 Algorithmic Efficiency
A supplemental blog on algorithmic efficiency. Learn how efficient algorithms solve problems faster and with less resource consumption.
Algorithmic Efficiency
Introduction
Algorithmic efficiency
refers to the resources an algorithm uses in terms of time and space (memory). Understanding algorithmic efficiency is crucial for writing programs that perform well, especially as the size of the input grows.
Objectives
By the end of this lesson, students will be able to:
- Understand what algorithmic efficiency is.
- Analyze the time complexity of algorithms using Big O notation.
- Write pseudocode and Python code to demonstrate efficient algorithms.
Key Concepts
Time Complexity
: A measure of the amount of time an algorithm takes to complete as a function of the length of the input.Space Complexity
: A measure of the amount of memory an algorithm uses as a function of the length of the input.Big O Notation
: A mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity.
Example Syntax (College Board Pseudocode)**
College Board pseudocode uses basic constructs to represent algorithms. Here is an example of a simple loop:
FOR i ← 1 TO n
{
// Code block to execute n times
}
`Example 1: Linear Search`
## Pseudocode
Let's write pseudocode for a linear search, which has a time complexity of O(n). This algorithm has a linear time complexity.
```python
index ← -1
FOR i ← 1 TO n
{
IF array[i] = target
{
index ← i
BREAK
}
}
DISPLAY index
Python
Here is the equivalent Python code:
def linear_search(array, target):
index = -1
for i in range(len(array)):
if array[i] == target:
index = i
break
return index
array = [1, 2, 3, 4, 5]
target = 3
print(linear_search(array, target)) # Output: 2
2
Example 2: Binary Search
Pseudocode
Let’s write pseudocode for a binary search, which has a time complexity of O(log n):
left ← 0
right ← n - 1
index ← -1
WHILE left <= right
{
mid ← (left + right) / 2
IF array[mid] = target
{
index ← mid
BREAK
}
ELSE IF array[mid] < target
{
left ← mid + 1
}
ELSE
{
right ← mid - 1
}
}
DISPLAY index
Python
Here is the equivalent Python code:
def binary_search(array, target):
left, right = 0, len(array) - 1
index = -1
while left <= right:
mid = (left + right) // 2
if array[mid] == target:
index = mid
break
elif array[mid] < target:
left = mid + 1
else:
right = mid - 1
return index
array = [1, 2, 3, 4, 5]
target = 3
print(binary_search(array, target)) # Output: 2
2
Example 3
Write pseudocode to implement a bubble sort, which has a time complexity of O(n^2). This algorithm has a polynomial time complexity.
FOR i ← 0 TO n - 1
{
FOR j ← 0 TO n - i - 1
{
IF array[j] > array[j + 1]
{
temp ← array[j]
array[j] ← array[j + 1]
array[j + 1] ← temp
}
}
}
DISPLAY array
Python
Here is the equivalent Python code:
def bubble_sort(array):
n = len(array)
for i in range(n):
for j in range(0, n-i-1):
if array[j] > array[j+1]:
array[j], array[j+1] = array[j+1], array[j]
return array
array = [5, 1, 4, 2, 8]
print(bubble_sort(array)) # Output: [1, 2, 4, 5, 8]
[1, 2, 4, 5, 8]
Example 3:
Write pseudocode to implement the insertion sort algorithm, which has a time complexity of O(n²). This algorithm has a polynomial time complexity (because n is to the power of a number)
FOR i ← 1 TO n - 1
{
key ← array[i]
j ← i - 1
WHILE j >= 0 AND array[j] > key
{
array[j + 1] ← array[j]
j ← j - 1
}
array[j + 1] ← key
}
DISPLAY array
Python
Here is the equivalent Python code:
def insertion_sort(array):
for i in range(1, len(array)):
key = array[i]
j = i - 1
while j >= 0 and key < array[j]:
array[j + 1] = array[j]
j -= 1
array[j + 1] = key
return array
array = [5, 1, 4, 2, 8]
print(insertion_sort(array)) # Output: [1, 2, 4, 5, 8]
[1, 2, 4, 5, 8]
Example 4:
Write pseudocode to implement the fibonacci algorithm, which has a time complexity of O(2^n). This means that is an exponential algorithm.
FUNCTION Fibonacci(n)
{
IF n <= 1
{
RETURN n
}
ELSE
{
RETURN Fibonacci(n-1) + Fibonacci(n-2)
}
}
DISPLAY Fibonacci(n)
Python
Here is the equivalent Python code:
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
fibonacci(30)
832040
Time Complexity Using Python Time Module
Now that we’ve considered some basic examples, let’s play around with how long different types of algorithms take. Remember, time is just one measure of algorithmic efficiency. Collegeboard considers linear/polynomial/logarithmic to be algorithms run in reasonable time, while exponential algorithms run in unreasonable time.
import time
# Linear Search
def linear_search(array, target):
index = -1
for i in range(len(array)):
if array[i] == target:
index = i
break
return index
array = list(range(1, 10001)) # Large array for timing
target = 9999
start_time = time.time()
linear_search(array, target)
end_time = time.time()
print(f"Linear Search Time: {end_time - start_time} seconds")
# Binary Search
def binary_search(array, target):
left, right = 0, len(array) - 1
index = -1
while left <= right:
mid = (left + right) // 2
if array[mid] == target:
index = mid
break
elif array[mid] < target:
left = mid + 1
else:
right = mid - 1
return index
start_time = time.time()
binary_search(array, target)
end_time = time.time()
print(f"Binary Search Time: {end_time - start_time} seconds")
# Bubble Sort
def bubble_sort(array):
n = len(array)
for i in range(n):
for j in range(0, n-i-1):
if array[j] > array[j+1]:
array[j], array[j+1] = array[j+1], array[j]
return array
array = [5, 1, 4, 2, 8]
start_time = time.time()
bubble_sort(array)
end_time = time.time()
print(f"Bubble Sort Time: {end_time - start_time} seconds")
# Fibonnaci
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
n = 30 # Choosing a smaller n for timing
start_time = time.time()
fibonacci(n)
end_time = time.time()
print(f"Fibonacci (Exponential) Time: {end_time - start_time} seconds")
Linear Search Time: 0.0003268718719482422 seconds
Binary Search Time: 3.719329833984375e-05 seconds
Bubble Sort Time: 3.1948089599609375e-05 seconds
Fibonacci (Exponential) Time: 0.230820894241333 seconds
Hacks
Review each of the sections above and produce …
- Write pseudocode and Python code to implement and time an insertion sort algorithm.
- Compare the performance of insertion sort (O(n^2)) with bubble sort (O(n^2)) for different sizes of input arrays.