0% found this document useful (0 votes)
4 views33 pages

04 Algorithm Analysis

Uploaded by

mofreh hogo
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
Download as ppt, pdf, or txt
0% found this document useful (0 votes)
4 views33 pages

04 Algorithm Analysis

Uploaded by

mofreh hogo
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1/ 33

CSE 373

Algorithm Analysis and Runtime Complexity

slides created by Marty Stepp


http://www.cs.washington.edu/373/

© University of Washington, all rights reserved.

1
Evaluating an algorithm
• How to know whether a given algorithm is good, efficient, etc.?

• One idea: Implement it, run it, time it / measure it (averaging trials)
 Pros?
• Find out how the system effects performance
• Stress testing – how does it perform in dynamic environment
• No math!
 Cons?
• Need to implement code (takes time)
• Can be hard to estimate performance
• When comparing two algorithms, all other factors need to be held constant
(e.g., same computer, OS, processor, load)

2
Range algorithm
How efficient is this algorithm? Can it be improved?
// returns the range of values in the given array;
// the difference between elements furthest apart
// example: range({17, 29, 11, 4, 20, 8}) is 25
public static int range(int[] numbers) {
int maxDiff = 0; // look at each pair of values
for (int i = 0; i < numbers.length; i++) {
for (int j = 0; j < numbers.length; j++) {
int diff = Math.abs(numbers[j] – numbers[i]);
if (diff > maxDiff) {
maxDiff = diff;
}
}
}
return diff;
}

3
Range algorithm 2
A slightly better version:
// returns the range of values in the given array;
// the difference between elements furthest apart
// example: range({17, 29, 11, 4, 20, 8}) is 25
public static int range(int[] numbers) {
int maxDiff = 0; // look at each pair of values
for (int i = 0; i < numbers.length; i++) {
for (int j = i + 1; j < numbers.length; j++) {
int diff = Math.abs(numbers[j] – numbers[i]);
if (diff > maxDiff) {
maxDiff = diff;
}
}
}
return diff;
}

4
Range algorithm 3
A MUCH faster version. Why is it so much better?
// returns the range of values in the given array;
// example: range({17, 29, 11, 4, 20, 8}) is 25
public static int range(int[] numbers) {
int max = numbers[0]; // find max/min values
int min = max;
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] < min) {
min = numbers[i];
}
if (numbers[i] > max) {
max = numbers[i];
}
}
return max - min;
}

5
Runtime of each version
• Version 1: Version 3:

• Version 2:

6
Max subsequence sum
• Write a method maxSum to find the largest sum of any contiguous
subsequence in an array of integers.
 Easy for all positives: include the whole array.
 What if there are negatives?

index 0 1 2 3 4 5 6 7 8
value 2 1 -4 10 15 -2 22 -8 5

Largest sum: 10 + 15 + -2 + 22 = 45

 (Let's define the max to be 0 if the array is entirely negative.)

• Ideas for algorithms?


7
Algorithm 1 pseudocode
maxSum(a):
max = 0.
for each starting index i:
for each ending index j:
sum = add the elements from a[i] to a[j].
if sum > max,
max = sum.

return max.

index 0 1 2 3 4 5 6 7 8
value 2 1 -4 10 15 -2 22 -8 5

8
Algorithm 1 code
• How efficient is this algorithm?
 Poor. It takes a few seconds to process 2000 elements.
public static int maxSum1(int[] a) {
int max = 0;
for (int i = 0; i < a.length; i++) {
for (int j = i; j < a.length; j++) {
// sum = add the elements from a[i] to a[j].
int sum = 0;
for (int k = i; k <= j; k++) {
sum += a[k];
}
if (sum > max) {
max = sum;
}
}
}
return max;
}

9
Flaws in algorithm 1
• Observation: We are redundantly re-computing sums.
 For example, we compute the sum between indexes 2 and 5:
a[2] + a[3] + a[4] + a[5]

 Next we compute the sum between indexes 2 and 6:


a[2] + a[3] + a[4] + a[5] + a[6]

 We already had computed the sum of 2-5, but we compute it again as


part of the 2-6 computation.

 Let's write an improved version that avoids this flaw.

10
Algorithm 2 code
• How efficient is this algorithm?
 Mediocre. It can process 10,000s of elements per second.
public static int maxSum2(int[] a) {
int max = 0;
for (int i = 0; i < a.length; i++) {
int sum = 0;
for (int j = i; j < a.length; j++) {
sum += a[j];
if (sum > max) {
max = sum;
}
}
}
return max;
}

11
A clever solution
• Claim 1 : The max range cannot start with a negative-sum range.
i ... j j+1 ... k
<0 sum(j+1, k)
sum(i, k) < sum(j+1, k)

• Claim 2 : If sum(i, j-1) ≥ 0 and sum(i, j) < 0, any max range that ends
at j+1 or higher cannot start at any of i through j.
i ... j-1 j j+1 ... k
≥0 <0 sum(j+1, k)
<0 sum(j+1, k)
sum(?, k) < sum(j+1, k)

 Together, these observations lead to a very clever algorithm...


12
Algorithm 3 code
• How efficient is this algorithm?
 Excellent. It can handle many millions of elements per second!
public static int maxSum3(int[] a) {
int max = 0;
int sum = 0;
int i = 0;
for (int j = 0; j < a.length; j++) {
if (sum < 0) { // if sum becomes negative, max range
i = j; // cannot start with any of i - j-1,
sum = 0; // (Claim 2) so move i up to j
}
sum += a[j];
if (sum > max) {
max = sum;
}
}
return max;
}

13
Analyzing efficiency
• efficiency: A measure of the use of computing resources by code.
 most commonly refers to run time; but could be memory, etc.

• Rather than writing and timing algorithms, let's analyze them.


Code is hard to analyze, so let's make the following assumptions:
 Any single Java statement takes a constant amount of time to run.
 The runtime of a sequence of statements is the sum of their runtimes.
 An if/else's runtime is the runtime of the if test, plus the runtime of
whichever branch of code is chosen.
 A loop's runtime, if the loop repeats N times, is N times the runtime of
the statements in its body.
 A method call's runtime is measured by the total of the statements
inside the method's body.
14
Runtime example
statement1;
2
statement2;

for (int i = 1; i <= N; i++) {


statement3;
statement4; 4N
statement5;
statement6; ½ N2 + 4N + 2
}

for (int i = 1; i <= N; i++) {


for (int j = 1; j <= N/2; j++) {
statement7; ½ N2
}
}

• How many statements will execute if N = 10? If N = 1000?


15
Algorithm growth rates
• We measure runtime in proportion to the input data size, N.
 growth rate: Change in runtime as N changes.

• Say an algorithm runs 0.4N3 + 25N2 + 8N + 17 statements.


 Consider the runtime when N is extremely large .
(Almost any algorithm is fine if N is small.)
 We ignore constants like 25 because they are tiny next to N.
 The highest-order term (N3) dominates the overall runtime.

 We say that this algorithm runs "on the order of" N3.
 or O(N3) for short ("Big-Oh of N cubed")

16
Growth rate example
Consider these graphs of functions.
Perhaps each one represents an algorithm:
N3 + 2N2
100N2 + 1000

• Which is better?

17
Growth rate example
• How about now, at large values of N?

18
Complexity classes
• complexity class: A category of algorithm efficiency based on the
algorithm's relationship to the input size N.

Class Big-Oh If you double N, ... Example


constant O(1) unchanged 10ms
logarithmic O(log2 N) increases slightly 175ms
linear O(N) doubles 3.2 sec
log-linear O(N log2 N) slightly more than doubles 6 sec
quadratic O(N2) quadruples 1 min 42 sec
cubic O(N3) multiplies by 8 55 min
... ... ... ...
exponential O(2N) multiplies drastically 5 * 1061 years

19
Java collection efficiency
Method Array Linked Stack Queue TreeSet [Linked] Priority
List List /Map HashSet Queue
/Map
add or put O(1) O(1) O(1)* O(1)* O(log N) O(1) O(log N)*
add at index O(N) O(N) - - - - -
contains/ O(N) O(N) - - O(log N) O(1) -
indexOf
get/set O(1) O(N) O(1)* O(1)* - - O(1)*
remove O(N) O(N) O(1)* O(1)* O(log N) O(1) O(log N)*
size O(1) O(1) O(1) O(1) O(1) O(1) O(1)

• * = operation can only be applied to certain element(s) / places

20
Big-Oh defined
• Big-Oh is about finding an asymptotic upper bound.

• Formal definition of Big-Oh:


f(N) = O(g(N)), if there exists positive constants c , N0 such that
f(N)  c · g(N) for all N  N0 .
 We are concerned with how
f grows when N is large.
• not concerned with
c*
small N or constant factors

 Lingo: "f(N) grows


no faster than g(N)."

21
Big-Oh questions
• N + 2 = O(N) ?
 yes
• 2N = O(N) ?
 yes
• N = O(N2) ?
 yes
• N2 = O(N) ?
 no
• 100 = O(N) ?
 yes
• N = O(1) ?
 no
• 214N + 34 = O(N2) ?
 yes

22
Preferred Big-Oh usage
• Pick the tightest bound. If f(N) = 5N, then:
f(N) = O(N5)
f(N) = O(N3)
f(N) = O(N log N)
f(N) = O(N)  preferred

• Ignore constant factors and low order terms:


f(N) = O(N), not f(N) = O(5N)
f(N) = O(N3), not f(N) = O(N3 + N2 + 15)

 Wrong: f(N)  O(g(N))


 Wrong: f(N)  O(g(N))
 Right: f(N) = O(g(N))

23
A basic Big-Oh proof
• Claim: 2N + 6 = O(N).
• To prove: Must find c, N0 such that for all N ≥ N0,
2N + 6 ≤ c · N

• Proof: Let c = 3, N0 = 6.
2N + 6 ≤ 3 · N
6 ≤N

24
Math background:
Exponents
• Exponents:
 XY , or "X to the Yth power";
X multiplied by itself Y times

• Some useful identities:


 XA · XB = XA+B
 XA / XB = XA-B
 (XA)B = XAB
 XN + XN = 2XN
 2N + 2N = 2N+1

25
Math background:
Logarithms
• Logarithms
 definition: XA = B if and only if logX B = A
 intuition: logX B means:
"the power X must be raised to, to get B"

 In this course, a logarithm with no base implies base 2.


log B means log2 B

• Examples
 log2 16 = 4 (because 24 = 16)
 log10 1000 = 3 (because 103 = 1000)

26
Logarithm bases
• Identities for logs with addition, multiplication, powers:
 log (A·B) = log A + log B
 log (A/B) = log A – log B
 log (AB) = B log A

• Identity for converting bases of a logarithm:


log C B
log A B 
log C A
 example:
log432 = (log2 32) / (log2 4)
=5/2
 Practically speaking, this means all logc are a constant factor away from
log2, so we can think of them as equivalent to log2 in Big-Oh analysis.
27
More runtime examples
• What is the exact runtime and complexity class (Big-Oh)?

int sum = 0;
for (int i = 1; i <= N; i += c) {
sum++;
}
 Runtime = N / c = O(N).

int sum = 0;
for (int i = 1; i <= N; i *= c) {
sum++;
}
 Runtime = logc N = O(log N).

28
Binary search
• binary search successively eliminates half of the elements.
 Algorithm: Examine the middle element of the array.
• If it is too big, eliminate the right half of the array and repeat.
• If it is too small, eliminate the left half of the array and repeat.
• Else it is the value we're searching for, so stop.

 Which indexes does the algorithm examine to find value 42?


 What is the runtime complexity class of binary search?

index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
value -4 2 7 10 15 20 22 25 30 36 42 50 56 68 85 92 103

min mid ma
x
29
Binary search runtime
• For an array of size N, it eliminates ½ until 1 element remains.
N, N/2, N/4, N/8, ..., 4, 2, 1
 How many divisions does it take?

• Think of it from the other direction:


 How many times do I have to multiply by 2 to reach N?
1, 2, 4, 8, ..., N/4, N/2, N
 Call this number of multiplications "x".

2x =N
x = log2 N

• Binary search is in the logarithmic (O(log N)) complexity class.


30
Math: Arithmetic series
• Arithmetic series notation (useful for analyzing runtime of loops):
k

 Expr
i j
 the sum of all values of Expr with each value of i between j--k

• Example:
4

 2i 1
i 0

= (2(0) + 1) + (2(1) + 1) + (2(2) + 1) + (2(3) + 1) + (2(4) + 1)


=1+3+5+7+9
= 25

31
Arithmetic series identities
• sum from 1 through N inclusive:
N
N N  1
 i 
2
O N 2

i 1

• Intuition:
 sum = 1 + 2 + 3 + ... + (N-2) + (N-1) + N
 sum = (1 + N) + (2 + N-1) + (3 + N-2) + ... // rearranged

// N/2 pairs total


• sumNof squares:
N N  12 N  1
 i 2

6
O 
N 3

i 1

32
Series runtime examples
• What is the exact runtime and complexity class (Big-Oh)?

int sum = 0;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N * 2; j++) {
sum++;
}
}
 Runtime = N · 2N = O(N2).

int sum = 0;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= i; j++) {
sum++;
}
}
 Runtime = N (N + 1) / 2 = O(N2).

33

You might also like