«««< HEAD
Format:
6f773b84df4a423f46d7877c931f9b87a6a230e5
Consider running time $\sim$ # elementary operations
$f, g$ are functions from natural numbers $\mathbf{N}$ to reals $\mathbf{R}$
E.g.,
Informally Write $f = O(g)$ to mean “$f$ scales no faster than $g$”
Definition. $f, g : \mathbf{N} \to \mathbf{R}^+$ We write $f = O(g)$ (read: “$f$ is (big) O of $g$”) if there exists a natural number $N$ and a constant $C$ in $\mathbf{R}^+$ such that for all $n \geq N$, we have
if $f(n) \leq c$ for all $n$ ($c$ constant), then $f = O(1)$
if $f(n) \leq g(n)$ for all $n$, then $f = O(g)$
if $f = O(g)$, then for all constants $c$, $c f = O(g)$
if $f, h = O(g)$ then $f + h = O(g)$
if $f_1 = O(g_1)$ and $f_2 = O(g_2)$, then $f_1 \cdot f_2 = O(g_1 \cdot g_2)$
Conesequnce:
Show: $10 n^2 + 100 n + 1000 = O(n^2)$
Assumptions
primitive operations take time $O(1)$
initializing objects of size $n$ (primitive data types) takes time $O(n)$
add(i, x)
? public void add(int i, E x) {
if (i < 0 || i > size) { throw new IndexOutOfBoundsException();}
Node<E> nd = new Node<E>();
nd.value = x;
if (i == 0) {
nd.next = this.head;
this.head = nd;
} else {
Node<E> pred = getNode(i - 1);
Node<E> succ = pred.next;
pred.next = nd;
nd.next = succ;
}
++size;
}
getNode(i)
? private Node<E> getNode(int i) {
// check if i is a valid index
if (i < 0 || i >= size) return null;
Node<E> cur = head;
// find the i-th successor of the head
for (int j = 0; j < i; ++j) {
cur = cur.next;
}
return cur;
}
ArraySimpleStack
?public class ArraySimpleStack<E> implements SimpleStack<E> {
private int capacity;
private int size = 0;
private Object[] contents;
...
public void push(E x) {
if (size == capacity) {
increaseCapacity();
}
contents[size] = x;
++size;
}
increaseCapacity()?
private void increaseCapacity() {
// create a new array with larger capacity
Object[] bigContents = new Object[2 * capacity];
// copy contents to bigContents
for (int i = 0; i < capacity; ++i) {
bigContents[i] = contents[i];
}
// set contents to refer to the new array
contents = bigContents;
// update this.capacity accordingly
capacity = 2 * capacity;
}
What is the running time of
SimpleStack<Integer> stk = new ArraySimpleStack<Integer>();
for (int i = 1; i <= n; i++) {
stk.push(i);
}
SimpleStack<Integer> stk = new ArraySimpleStack<Integer>();
for (int i = 1; i <= n; i++) {
stk.push(i);
}
push
is $O(n)$
push
es have running time $n \cdot O(n) = O(n^2)$push
are performed in $O(1)$ timepush
$n$ times empirical running time looks like $O(n)$, not $O(n^2)$.“cost” of an operation $\approx$ running time of operation
Idea. Don’t look at worst-case cost of each operation individually
instead look at worst-case cost of any sequence of operations
amortized cost is the average cost per operation of any such sequence
Cost of living:
«««< HEAD Income:
Question:
I get paid daily $100 (tax free)
Some days, I need to pay $1,905… how can I afford to live on $100 a day?!?
6f773b84df4a423f46d7877c931f9b87a6a230e5
Open a bank account!
«««< HEAD Each day, can do: ======= Each day, can do
6f773b84df4a423f46d7877c931f9b87a6a230e5
«««< HEAD I can afford to live off $100 a day if every day I can pay that day’s expenses and maintain non-negative bank account balance
6f773b84df4a423f46d7877c931f9b87a6a230e5
push(x)
Assume initially size = capacity = 1
for (int i = 1; i <= n; i++) {
stk.push(i);
}
What are costs of operations?
«««< HEAD
push
public void push(E x) {
if (size == capacity) {
increaseCapacity();
}
contents[size] = x;
++size;
}
increaseCapacity
when size
$= n$ is $C_n$
What is $C_n$ in big O notation?
increaseCapacity()
Code private void increaseCapacity() {
// create a new array with larger capacity
Object[] bigContents = new Object[2 * capacity];
// copy contents to bigContents
for (int i = 0; i < capacity; ++i) {
bigContents[i] = contents[i];
}
// set contents to refer to the new array
contents = bigContents;
// update this.capacity accordingly
capacity = 2 * capacity;
}
push
public void push(E x) {
if (size == capacity) {
increaseCapacity();
}
contents[size] = x;
++size;
}
Suppose current capacity is $n$
Each push
until next resize
Question. How much to add?
At next increaseCapacity()
call, what is account balance?
How to pay $C_n$ for increaseCapacity()
?
If $n/2$ was last resize, each push
until size is $n$:
push
On push when size is $n$
push
increaseCapacity()
In both scenarios
=======
6f773b84df4a423f46d7877c931f9b87a6a230e5