# Comparing Functions (14 points)

For the following pairs of functions, indicate whether the ?? could be replaced with $O$, $\Omega$ or $\Theta$.

Pr. | $f(n)$ | $g(n)$ | $f(n) \in ?? (g(n))$ |
---|---|---|---|

a) | $48 n$ | $2 n^2 + 1$ | $O$ |

b) | $0.00001n^2$ | $2^{2^{10}} (n \log n)$ | $\Omega$ |

c) | $5 n^{20} + n^2\log_2 n$ | $n !$ | $O$ |

d) | $4 n$ | $4 \log_2 (2^n)$ | $\Theta$ |

e) | $5 n \log n$ | $2 n^{1.5}$ | $O$ |

f) | $7 n^{1024}$ | $1.000001^n$ | $O$ |

g) | $\frac{2 n^2}{\log n}$ | $3 n$ | $\Omega$ |

# Orders of Functions (14 points)

List each of the functions from the previous problem from slowest to fastest growing in a table like the table below (include both the $f(n)$ and $g(n)$ functions). Group the functions by complexity class. Indicate which functions are in the same complexity class (same big-$\Theta$ set).

Complexity class | Functions from previous problem. |
---|---|

$\Theta(n)$ | $48n$, $4n$, $4\log_2 (2^n)$, $3n$ |

$\Theta(n\log n)$ | $2^{2^{10}}(n\log n)$, $5n\log n$ |

$\Theta(n^{1.5})$ | $2 n^{1.5}$ |

$\Theta(n^2)$ | $0.00001n^2$, $2n^2 + 1$ |

$\Theta(\frac{n^2}{\log n})$ | $\frac{2n^2}{\log n}$ |

$\Theta(n^{20})$ | $5n^{20} + n^2\log_2 n$ |

$\Theta(n^{1024})$ | $7n^{1024}$ |

$\Theta(1.000001^n)$ | $1.000001^n$ |

$\Theta(n!)$ | $n!$ |

**NOTE: You may not need all of the rows in the table above.**

# Analyzing Java Code (12 points)

For each of the following Java methods, analyze the running time by:

- writing an expression in terms of $n$ for the every-time case analysis $T(n)$ (if it exists) or worst case analysis $W(n)$ (if the every-time case analysis does not exist) for the
*number of arithmetic operations*, - give the appropriate big-$\Theta$ complexity class for your analysis function $T(n)$ or $W(n)$.

*Code Listing A*

```
public int A(int[] array) {
int result = 25;
int i = array.length;
while (i > 1) {
if (array[i-1] < 0) { // 1 op
return 0;
}
for (int j = 0; j < array.length; j++) {
result += 1;
result += 3 * array[j];
} // 4 operations per iteration, 4n per iteration of outer loop
i = i / 2; // 1 op
// So this loop does 2 + 4n operations each iteration
} // This occurs (log n + 1) times, though we are flexible if you got (log n)
return result;
}
```

- Give your equation for $T(n)$ or $W(n)$ (which did you choose and why)? $W(n) = (\log n + 1) (4n + 2) = 4n \log n + 4n + 2\log n + 2$. We used $W(n)$ because there is no every-case time complexity since the if statement in the loop exits the method early in the event that
`array[i-1] < 0`

. - Give the $\Theta$ complexity class: $\Theta(n\log n)$

*Code Listing B*

```
public int B(int[] array1) {
int result = 0;
for (int i = 0; i < array1.length / 2; i++) {
result += array1[i] * 2;
} // 4 ops per iteration plus one extra divide, n/2 iterations, total : 4n/2 + 1 = 2n + 1
for (int j = array1.length-1; j >= 0; j--) {
result += array1[j] * 3;
} // 3 ops per iteration, plus one extra for initialization of j, so 3n + 1
return result;
}
```

- Give your equation for $T(n)$ or $W(n)$ (which did you choose and why)? $T(n) = 5n + 2$. Every-time case because loop iteration count doesn’t depend on input values.
- Give the $\Theta$ complexity class: $\Theta(n)$

*Code Listing C*

```
public int C(int[] array1) {
int result = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1.length; j++) {
for (int k = 1; k < array1.length; k = k * 2) {
result += j * j * array1[k] + array1[i] + array1[j];
} // 6 ops per iteration, log n + 1 iterations: 6log n + 6 total
} // 6log n + 7 ops per iteration, n iterations, 6 n log n + 7 n total
} // 6 n log n + 7n + 1 ops per iteration, n iterations, 6n^2 log n + 7n^2 + n ops total
return result;
}
```

- Give your equation for $T(n)$ or $W(n)$ (which did you choose and why)? $T(n) = 6 n^2\log n + 7 n^2 + n$ (Every-time since it doesn’t depend on the values of array1, just the length.)
- Give the $\Theta$ complexity class: $\Theta(n^2\log n)$.

# How much faster? (6 points)

Suppose you have an algorithm that performs $T(n) = 8 n^3$ arithmetic operations on an input of size $n$. Suppose you have two machines, machine A and machine B. Machine A performs 10 arithmetic operations per second, while machine B performs 20 arithmetic operations per second.

- What is the largest input size $n_A$ you can compute on machine A in 60 seconds?
- What is the largest input size $n_B$ you can compute on machine B in 60 seconds?
- Write an equation describing the relationship between $n_A$ and $n_B$.

The easiest way to solve this is to recognize that if machine A runs 10 ops per second and we run it for 60 seconds, then it will have performed 600 ops. Thus we are asking for what value of $n_A$ is $8 n_A^3 = 600$. Solving for $n_A$ we get $n_A = \sqrt[3]{75}$.

If machine B runs in 20 ops per second, and we run it for 60 seconds, then it performs 1200 ops. Thus $8 n_B^3 = 1200$. Solving for $n_B$ we get $n_B = \sqrt[3]{150}$.

Finally, notice that $8 n_A^3 = 600$ and $8 n_B^3 = 1200$. Thus $8 n_B^3 = 1200 = 2 * 600 = 2 (8 n_A^3)$. Solving for $n_B$ we get that $n_B^3 = 2 n_A^3 \Rightarrow n_B = \sqrt[3]{2} n_A \approx (1.26 n_A)$. In other words, if we double the speed of our machine, the size of the problem we can solve in a fixed time frame only increases by a factor of $1.26$.