02b: Algorithms: Big-O
ICS211, Fall 2012
Dr. Zach
(switch view)
Status
- Tamarin (up and down, hopefully fixed)
- Today: last day to add.
- Everything due tonight (8am, Thurs)
- Switching from xhtml to html starting with these slides
- please report any technical problems not encountered in 01A - 02A slides
- A03 now posted.
- LAs have open lab hours (WF, 6-9pm, on Syllabus).
Comparing Algorithms
- (See/add to Laulima forums discussion for important factors)
- Efficiency
- if both solve same problem
- time, but also space/memory
- First thought: just code them both and time them!
Comparing Implementations
- Many implementation details captured in timing (benchmarking)
- coder differences (loop types, methods used, etc.)
- language factors (start-up time, garbage collection, compiler optimizations)
- hardware factors (across machines, hardware boundaries)
- timing accuracy limits
- So benchmarking does not compare algorithm performance
Comparing Algorithms: Number of steps involved?
- But what is a single step?
- x = x + 4
- x = x - y * 2
- nums = sort(nums)
Comparing Algorithms: Worst-case growth rate!
- How does the algorithm perform under stress? (add more elements to process)
- Basically categorize growth rate: linear, quadratic, logarithmic, etc.
- ignore the finer details
- still a good way to compare to different algorithms
- gives us a single measure
- worst-case
- Start with counting "steps", but then drop the details to see only measure change with problem size
Example (variant of p.81)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
//statement 1
//statement 2
}
}
for (int k = 0; k < n; k++) {
//statement 1
//statement 2
//...
//statement 5
}
//25 more statements
Time to run = T(n) = n*n*2 + n*5 + 25 = 2n2 + 5n + 25
(assuming each statement takes 1 tick to run)
Big-O Definition Example
- Problem: T(n) = 2n2 + 5n + 25
- From def: T(n) = O(f(n)) iff T(n) <= c * f(n) for some n > n0 and c
- Select n0 = 5 and c = 4 and f(n) = n2 (or other higher values)
- T(n) <= cf(n): 2n2 + 5n + 25 <= 4 * n2
- 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(n2)
(Note we could have selected f(n) = n4 here instead. Valid, but convention (especially in this class) is to choose the simplest and lowest-order f(n) that you can.)
Big-O Definition Revisited
- Big-O is worst case. (Big-Ω = best case, Big-Θ = always; both best and worst.)
- Big-O also used for space growth and more generally for other functions.
- asymptotic (that is, usually as n -> ∞)
>
- Formally, T(n) = O(f(n)) should be T(n) ∈ O(f(n))
- Can have more than one variable (ie, m and n).
Informal Approach
- T(n) = 2n2 + 5n + 25 = O(2n2 + 5n + 25) (c = 1, n0 = 0)
- Drop all lower-order terms: T(n) = O(2n2) (by selecting some higher c and n0)
- Drop any constants: T(n) = O(n2) (by selecting some even higher c)
- So you can usually just look at the code and see the big-O... but some tricks to this.
Summary: Big-O tells us the algorithm won't get any worse than a given f(n), no matter how many more processed elements are added.
Big-O Example: Search (p.78)
/** Returns index of target found in x array, or -1 if not found */
public static int search(int[] x, int target) {
for (int i = 0; i < x.length; i++) {
if (x[i] == target) {
return i;
}
}
return -1; //looped through whole array and didn't find target
}
- What corresponds to n (variable input size) here? x.length
- What's best/worst/average case in terms of n?
- Big-O?
O(n)
Big-O Example: Box
/** 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 (variable input size) here?
m = width, n = height
- Big-O? O(m * n) (or O(n^2) if assuming very worst case m=n)
- As a square? m = n, so O(n^2)
Big-O Example: Many boxes
/** 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 corresponds to n here?
size
- Big-O? O(n^2) if including drawBox too (which we probably should)
- What if we consider the contents of drawBox vs if we don't?
If treating drawBox call as a single step, then O(1) (since for loop always executes 5 times and does not vary with n)
Big-O Example: Many boxes variant
/** 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();
}
}
- What corresponds to n here?
many
- Big-O?
O(n) (since drawBox is a constant cost now: 10 x 10)
- If we replace drawBox(10,10) with drawBox(many, many) then O(n^3)
Big-O Example: Find duplicates
/** 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;
}
- What corresponds to n here?
nums.length
- Big-O?
O(n^2) (even though second loop does not start at 0)
Lessons from Examples
- Look for loops, since they act as "multipliers" on their contained statements.
- The number of other statements doesn't really matter ("constants" that will get dropped)
- But not every loop does more work as the size of the input increases!
- (Soon you'll have apply this to recursive calls, so it's not only loops that cause big-O growth.)
- Common big-Os: O(1), O(log n), O(n), O(n log n), O(n2), O(n3), O(2n), O(n!).
Some Big-O Limitations: vs reality
- Constants are dropped (but may be very large in practice)
- As n goes to infinity (but usually n is small in practice)
- Worst-case (but sometimes worst-case is rare in practice)
Java Review
Arrays and reading from a file
Arrays
int[] nums = {5, 6, 90};
int[] ages = new int[10];
int size = nums.length;
nums[1] = 60;
for (int i = 0; i < nums.length; i++) { //use .length, not 3 here
nums[i]++;
}
for (int n : nums) {
System.out.println(n);
}
Should already know this (esp. after Fri's lab).
Arrays of Arrays (Multi-dimensional)
char[][] ticTacToe = new char[3][3];
tictactoe[1][1] = 'X';
char[] middleRow = ticTacToe[1];
System.out.println(middleRow[1]);
int[][] matrix = new int[4][]; //sub-arrays can be different size if created later
for (int i = 0; i < matrix.length; i++) {
matrix[i] = new int[i + 1];
}
matrix[1][1] = 9;
Command Line Arguments
public class Hello {
public static void main(String[] args) {
//...
}
}
- Running on the command line:
java Hello
- JVM starts up, loads Hello.class, and calls the main method
- JVM passes any remaining arguments as elements of args array
- cmd line args == arguments to whole program (what gets done with them depends on program)
Cmd line args examples
java Hello one two
(args: ["one", "two"])
java Hello 3
(args: ["3"])
java Hello
(args: [])
- To use command line args: run your program on the command line!
- (Or figure out how to pass arguments in your IDE.)
Reading from a file
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
public class PrintFile {
/** Prints to the screen the contents of the file named input.txt. */
public static void main(String[] args) {
try {
Scanner file = new Scanner(new File("input.txt"));
while (file.hasNextLine()) {
String line = file.nextLine();
System.out.println(line);
}
file.close();
}catch (IOException e) {
System.out.println("Could not read from file: " + e.getMessage());
}
}
}
Reading from a file details
- Need to catch IOException (or FileNotFoundException), a checked exception
- Need to use hasNextLine() to find out if there is more to read from file.
- See Scanner class in API docs for more:
hasNext(), hasNextInt()
, etc.
- Here, I hard-coded "input.txt" as a literal.
- Careful:
new Scanner(new File(...))
. (Don't forget the new File
part)
- Using Scanner: just one way to do it
Reading from a file: Alternative
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
public class Hello {
/** Prints to the screen the contents of the file named input.txt. */
public static void main(String[] args) {
try {
BufferedReader file = new BufferedReader(new FileReader("input.txt"));
String line = file.readLine();
while (line != null) {
System.out.println(line);
line = file.readLine();
}
}catch (IOException e) {
System.out.println("Could not read from file: " + e.getMessage());
}
}
}
Interesting aside
String line = file.readLine(); //initializer
while (line != null) { //condition
System.out.println(line);
line = file.readLine(); //"increment"
}
Those are the components of a for loop...
for (String line = file.readLine(); line != null; line = file.readLine()) {
System.out.println(line);
}
Could have done something like this with Scanner too.
For next time...
- Quiz 02 (to be posted)
- A03 posted (due in 1 week; uses today's Java stuff)
- Lab x 2
- Monday == Holiday (Labor Day)
- My office hours: Tuesday instead.
- As always, deadlines and news will be on course website main page