Skip to content
MarkMcDermott edited this page Sep 14, 2013 · 3 revisions

Big-O

Notes adapted from Zach Tomaszewski

How do we compare algorithms?
  • Do multiple algorithms solve the same problem?
  • Do multiple algorithms run in the same amount of time?
  • Do multiple algorithms use the same amount of memory?
Benchmarking

Benchmarking is the act of timing how long it takes for a particular piece of code to run. It's possible to measure

  • Clock time
  • Processor time
  • Memory consumption

However, there are many areas where benchmarking can give incorrect results

  • Language factors (start-up time, garbage collection, compiler optimizations)
  • Code differences (loop types, methods used, etc)
  • Hardware factors
  • Data set size
  • Timing accuracy

Benchmarking is not a good measure of algorithm performance. We need something more abstract.

Counting the number of steps in an algorithm

What constitutes a single step?

x = x + 4
x += 4
x = x - 8 * 2
swap(x, y)
Upper-bound of growth rate
  • How does an algorithm perform under stress? (i.e. addition of more data to process)
  • Algorithms can be categorized by growth rate
  • Ignore the finer details
  • Uses a single measure
  • Measure is a function, so informative over a range of possible values
  • Guaranteed upper bound of worse-case
  • Good way to compare different algorithms
  • Start by counting "steps", but then drop the details to see the bigger picture

Assuming each statement takes 1 "step" to run, what's the runtime of the following algorithm?

for (int k = 0; k < n; k++) {
  //statement 1
  //statement 2
  //...
  //statement 5
}
//...25 more statements...
for (int i = 0; i < n; i++) {
  for (int j = 0; j < n; j++) {
    //statement 1
    //statement 2
  }
}
Definition of Big-O
  • Let n be the size of the data
  • T(n) = O(f(n)) as n -> ∞ iff there exist constants n0 >= 0m and c > 0 such that for all n > n0, T(n) <= cf(n)
  • T(n) = O(f(n)) shortcut notation for T(n) ∈ O(f(n))
Example
  • T(n) = 2n^2 + 5n + 25
  • T(n) = O(f(n)) iff T(n) <= cf(n) for some n > n0 and c
  • T(n) <= cf(n) ... 2n^2 + 5n + 25 <= cf(n)
  • Select n0 = 5 and c = 4 and f(n) = n^2 (or other higher values)
  • T(n) <= cf(n): 2n^2 + 5n + 25 <= 4 * n^2
  • For n = n0 = 5: 50 + 25 + 25 <= 4 * 25. (100 <= 100)
  • For any higher n (such as 6): 72 + 30 + 25 <= 4 * 36. (127 <= 144)
  • And so on
  • Therefore: T(n) = O(n^2) for c = 4 and n0=5
Big-O Definition Revisited
  • Big-O is upper-bound (worse-case)
  • Big-Ω (omega) is lower-bound
  • Big-Θ (theta) bounded by upper and lower-bound
  • Also used for space growth and generally for other functions
  • Asymptotic (that is, usually as n -> ∞)
  • Can have more than one variable, (n, m, etc)
Dropping the Details
  • Given T(n) = 2n^2 + 5n + 25
  • Drop all lower-order terms: T(n) = O(2n^2)
  • Drop any coefficients: T(n) = O(n^2)
  • Usually it's easy to infer Big-O by looking at the code, but it can get tricky (recursion)

Summary: Big-O tells us the algorithm won't grow any faster (get any worse) than a given f(n), no matter how many more processed elements are added.

Examples
/**
 * Search through array for target, return the index of the target or -1 if target is not in the array.
 * @param x Array to search through.
 * @param target Value to search for.
 * @return The index of the target or -1.
 */
public static int search(int[] x, int target) {
  for (int i = 0; i < x.length; i++) {
    if (x[i] == target) {
      return i;
    }
  }
  return -1;
}
  • What corresponds to n?
  • What's the best/worst/average case in terms of n?
  • Big-O?
/** Prints the given array forward and then backwards. */
public static void backAndForth(int[] nums) {
  //forward
  for (int n : nums) {
    System.out.print(n);
    System.out.print(" ");
  }
  System.out.println();

  //backwards
  for (int i = nums.length - 1; i >= 0; i--) {
    System.out.print(nums[i]);
    System.out.print(" ");
  }
  System.out.println();
}
  • Big-O?
/** Prints a box of #s of width * height.  */
public static void drawBox(int width, int height) {
  for (int row = 0; row < height; row++) {
    for (int col = 0; col < width; col++) {
      System.out.print('#');
    }
    System.out.println();
  }
}
  • What corresponds to n here?
  • Big-O?
  • As a square (n == m)
/** Prints 5 boxes of the given size.  */
public static void drawBoxes(int size) {
  for (int i = 0; i < 5; i++) {
    drawBox(size, size);
    System.out.println();
  }
}
  • What happens if we consider drawBox at a single step (O(1))?
/** Prints the given number of boxes.  */
public static void drawBoxes(int many) {
  for (int i = 0; i < many; i++) {
    drawBox(10, 10);
    System.out.println();
  }
}
  • Big-O? O(n) (since drawBox is a constant cost now: 10 x 10)
  • If we replaced drawBox(10,10) with drawBox(many, many)? O(n^3)
/** Returns whether there are any repeated values in the given array. */
public static boolean findDuplicates(int[] nums) {
  for (int i = 0; i < nums.length; i++) {
    for (int j = i + 1; j < nums.length; j++) {
      if (nums[i] == nums[j]) {
        return true;
      }
    }
  }
  return false;
}
  • Big-O?
Algorithms that run faster than n
  • Example: Binary search
Determining Big-O

Big-O plotted

Limitations
  • Constants are dropped but can be very big in practice... consider the following:
  • 2000n = O(n) vs 2n^2 = O(n^2)
  • n=10 ... 20,000 vs 200
  • n=1000 ... 2 million vs 2 million
  • n = 10,000 ... 20 million vs 200 million
  • n = 1,000,000 ... 2 billion vs 2e+12
  • Usually upper-bound of worse-case, but sometime worst case is rare in practice (quicksort)

List Interface

ArrayList basics
  • Resizable
  • Generic
  • Autoboxes primitive types

Some of the common operations include

  • boolean add(E e)
  • void add(int index, E element)
  • void clear()
  • boolean contains(Object o)
  • E get(int index)
  • E remove(int index)
  • boolean remove(Object o)
  • int size()
Implementation of ArrayLists
  • Backed by an array
  • As the size of an ArrayList grows, new arrays must be created to compensate

What is the Big-O for a list built on an array?

  • Adding to the list - O(n)
  • Getting from the list - O(1)
  • Removing from the list - O(n)
  • Getting the size - O(1)

Clone this wiki locally