Lecture 006

Big O Notation

f(n) is in O(g(n)) iff there exists C and N such that f(n) <= c * g(n) for all n >= N

Work Analysis

Work analysis for rev(list)

W_{rev}(n) where n is the length of the argument
W_{rev}(0) = C_0

W_{rev}(n) where n > 0
W_{rev}(n) = C_1 + W_{rev}(n-1) + W_{append}(n-1, 1) (cite: spec. of rev)
          <= C_1 + W_{rev}(n-1) + C_2 * n (cite: complexity of append)
           = C_1 + (C_1 + W_{rev}(n-2) + C_2 * (n-1)) + C_2 * n
           = C_1 * n + C_2 * (n + (n-1) + ... + 1) + C_0
           = C_1 * n + C_2 * (n(n+1)/2) + C_0
           = (n^2 + n)(C_2/2) + C_1 * n + C_0
So rev X runs in O(n^2) work, where n = length of x

Work analysis for tail recursive trev

(* trev: (int list * int list) -> int list
REQUIRES: true
ENSURES: trev (L, acc) ~= rev L @ acc
*)
fun trev ([]: int list, acc : int list): int list = acc
  | trev (x::xs, acc) = trev (xs, x::acc)

W_{rev} (n, m) where n, m are the length of the arguments
W_{rev} (0, m) = C_0 (for all m)
W_{rev} (n, m) = C_1 + W_{rev} (n-1, m+1) (for all n> 0, all m)


=== Solving it ===
W_{rev} (n, m) = C_1 + W_{rev} (n-1, m+1)
               = C_1 + C_1 + W_{rev} (n-2, m+2)
               = k * C_1 + W_{rev} (n - k, m + k) for k = n
               = n * C_1 + W_{rev} (0, m + n)
               = n * C_1 + C_0
O(n)

Work analysis for tree

datatype tree = Empty | Node of tree * int * tree
(*sum: tree -> int
REQUIRES: true
ENSURES: sum t |-> sum of the ints in T
*)
fun sum (Empty : tree) : int = 0
  | sum (Node (l, x, r)) = sum l + x + sum r

W_{sum}(n) where n is the number of node in the tree
W_{sum}(0) = C_0
W_{sum}(n) = C_1 + W_{sum}(n_l) + W_{sum}(n_r) (for n > 0)
           where n_l are number of left tree node
           where n_r are number of right tree node
           and n_l + n_r = n - 1

W_{sum}(n) = C_1 * n + C_0 * (n-1) (since number of leaf is the 1+ number of node)
           = (C_1 + C_0) * n + C_0
O(n)

Span analysis for tree using node

S_{sum} (0) = C_0
S_{sum} (n) = c_1 + max(S_{sum}(n_l), S_{sum}(n_r)) (for n > 0)


=== Solving it ===
If balanced: S_{sum} (n_l) = S_{sum} (n_r) = (n-1)/2

S_{sum}(n) <= C_1 + S_{sum}(n/2)
           <= C_1 + C_1 + ... + C_1 + C_0
            = C_1 * log(n) + C_0
O(log(n))

If perfectly unbalanced: n_l = n - 1, n_r = 0

S_{sum}(n) = C_1 + S_{sum} (n-1) (assume larger input take more running time when we solve max, using monatonity)
           = n*C_1 + C_0
O(n)

Span analysis for tree using depth

S_{sum}(d) where d is the depth of the input
S_{sum}(0) = C_0
S_{sum}(d) <= C_1 + max(S_{sum}(d-1), S_{sum}(d')) with d>0, d'<=d-1
            = C_1 + S_{sum}(d-1)
            = d * C_1 + C_0
O(d)

Work analysis for Sorting

(* ins: int * int list -> int list
REQUIRES: L is sorted
ENSURES ins(x, L) \-> a sorted permutation of x::L
*)
fun ins (x, []) = [x]
  | ins (x, y::ys) = case compare (x, y) of
  GREATER => y :: ins (x, ys)
  | _ => x :: y :: ys_

fun isort ([] : int list) : int list = []
  | isort (x :: xs) = ins (x, isort(xs))

W_{ins} (0) = C_0
W_{ins} (n) <= C_1 + W_{ins} (n-1)
             = n * C_1 + C_0
W_{ins}(n) = O(n)
S_{ins}(n) = O(n)

W_{isort} (n) = C_1 + W_{isort} (n-1) + W_{ins} (n-1) <= C_1 + W_{isort} (n-1) + (n-1)*C_2
W_{isort} is O(n^2)
S_{isort} is O(n^2)

Table of Content