Understanding Big O Notation: A Comprehensive Guide

Muhammad Alfiansyah
3 min readJun 28, 2024

--

Photo by Luca Bravo on Unsplash

The longer I spend in the programming world, the more I feel like I don’t know anything. There are so many areas I’m unfamiliar with, even though I’m focused only on Swift and iOS. As technology continues to evolve, I feel like I’m stuck and not progressing. Additionally, the IT industry has become increasingly challenging, and there aren’t as many job opportunities as there were a few years ago.

Introduction

What is Big O Notation?

Big O notation is a mathematical notation used in computer science to describe the performance or complexity of an algorithm. It characterizes functions according to their growth rates: how quickly they grow relative to the size of the input.

Key Concepts of Big O Notation

  • Time Complexity

Measures the amount of time an algorithm takes to complete as a function of the size of the input data.

  • Space Complexity

Measures the amount of memory an algorithm uses relative to the size of the input data.

Importance in Computer Science

Big O notation is crucial in computer science for several reasons:

  • Performance Analysis (Time Efficiency, Space Efficiency)
  • Algorithm Comparison (Benchmarking, Scalability)
  • Optimization (Identifying Bottlenecks, Resource Management)
  • Theoretical Foundation
  • Practical Applications (Real-World Problem Solving)
  • Educational Value

Common Big O Notations

O(1) — Constant Time

func getFirstElement(arr: [Int]) -> Int? {
return arr.first
}

O(n) — Linear Time

func printAllElements(arr: [Int]) {
for element in arr {
print(element)
}
}

O(n²) — Quadratic Time

func printAllPairs(arr: [Int]) {
for i in 0..<arr.count {
for j in 0..<arr.count {
print("\(arr[i]), \(arr[j])")
}
}
}

O(log n) — Logarithmic Time

func binarySearch(arr: [Int], target: Int) -> Int? {
var left = 0
var right = arr.count - 1

while left <= right {
let mid = (left + right) / 2

if arr[mid] == target {
return mid
} else if arr[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}

return nil
}

O(n log n) — Linearithmic Time

func mergeSort(_ array: [Int]) -> [Int] {
guard array.count > 1 else { return array }

let middleIndex = array.count / 2
let leftArray = mergeSort(Array(array[0..<middleIndex]))
let rightArray = mergeSort(Array(array[middleIndex..<array.count]))

return merge(leftArray, rightArray)
}

func merge(_ left: [Int], _ right: [Int]) -> [Int] {
var leftIndex = 0
var rightIndex = 0

var orderedArray: [Int] = []

while leftIndex < left.count && rightIndex < right.count {
if left[leftIndex] < right[rightIndex] {
orderedArray.append(left[leftIndex])
leftIndex += 1
} else if left[leftIndex] > right[rightIndex] {
orderedArray.append(right[rightIndex])
rightIndex += 1
} else {
orderedArray.append(left[leftIndex])
leftIndex += 1
orderedArray.append(right[rightIndex])
rightIndex += 1
}
}

while leftIndex < left.count {
orderedArray.append(left[leftIndex])
leftIndex += 1
}

while rightIndex < right.count {
orderedArray.append(right[rightIndex])
rightIndex += 1
}

return orderedArray
}

Conclusion

The importance of Big O notation in computer science cannot be overstated. It provides a clear and concise way to describe the efficiency of algorithms, facilitates the comparison and optimization of solutions, and forms the backbone of theoretical and practical aspects of the field. Whether for academic purposes, professional development, or real-world problem-solving, understanding Big O notation is essential for any computer scientist or software developer.

--

--