/////// init /////////
int a[n];
for ( int i=0; i<n; ++i ) {
a[i] = i+1;
}
//n assignments
//n comparisons
//n increments
//n additions
n*T(as)+n*T(co)+n*T(in)+n*T(ad)
// f(n) = Cn = O(n)
/////// find
int n = 0;
while (x != a[n]) {
++n;
}
// 1...n comparisons
// best, average, worst case scenarios
// if val is IN array
// otherwise
// 1 if a[0] == x
// n if a[size-1] == x, or x is not in the array
/////// binary search
int a[n] = { .... }; // sorted
int end = n;
int begin = 0;
while ( end-begin > 0 ) {
if ( a[ (begin + end) /2 ] > val ) { end = (begin + end) /2; }
else if ( a[ (begin + end) /2 ] < val ) { begin = (begin + end) /2; }
else {
return (begin + end) /2; // found
}
}
return n; // not found
// Analysis:
// Best case - number we are searching for is exactly in the middle, so
// after 2 if-statements we return. So constant time.
// Worst case - 2*log_2 m comparisons
//
// Explanation:
// Keep track of the size as it changes from one iteration to another:
// size: n -> n/2 -> n/2^2 -> ... -> n/2^k -> .... -> 1=n/2^m
// iterations: 0 1 2 k m (last) <-- unknown
// Solve for m:
// 2^m=n
// log_2 (2^m) = log_2 (n)
// log_2 ( exp_2 (m) ) = log_2 (n)
// m = log_2 (n)
// Using big-O to "predict" computation time:
// Algorithm O( N )
// N=10 - 1s (algorithm runs in 1 second on input of size 10)
// N=100 - ? (how long will it take on input of size 100
// Assume actual run-time is kN (k is a constant), then
// k*10 = 1
// What is k*100?
// k*100 = k*10 * 10 = 1 * 10 = 10 seconds
//
// Algorithm O( N^2 )
// N=10 - 1s
// N=20 - ?
// N=100 - ?
// N=1000 - ?
// Proof:
// Assume
// O(N^2) = K*N^2
//
// K*10^2 = 1 - given
//
// K*20^2 = K*(10*2)^2 = K*10^2*2^2 = 1sec * 2^2
//
// Algorithm O( N^3 )
// N=10 - 1s
// N=20 - 8 sec
// N=100 - 1000 sec
// N=1000 - (100)^3 sec = 1,000,000 s = 16666.666 min = 277.778 h = 11.57 days
// Proof:
// O(N^3) = K*N^3
// K*10^3 = 1
// K*20^3 = K*(10*2)^3 = K*10^3*2^3 = 1sec * 2^3 = 8 sec
//
// Note that the exact value of N is not important - only the "increase" of the input:
// Consider the same problem as before
// Algorithm O( N^3 )
// some N - 1s
// what is the run-time on 10*N?
// Solution:
// O(N^3) = K*N^3
// K*N^3 = 1
// K*(2N)^3 = K*(N*2)^3 = K*N^3*2^3 = 1sec * 2^3 = 8 sec
//
//
// Algorithm O(NlogN)
// N=100 - 1s
// what is the time for N=200
// Assume the actual run-time is K*N*logN,
// assume log base is 2
// then K*100*log 100 = 1, so that K = 1/(100*log 100) = 0.00150515
// calculate K*200*log 200 = 0.00150515*200*log 200 = 2.3010302
//
// Note that the "slow down" depends on N: consider the same problem when input
// incresases by a factor of 2, but the initial size is 10 instead of 100:
// N=10 - 1s
// N=20 - ??
// Assume the actual run-time is K*N*logN,
// then K*10*log 10 = 1, so that K = 1/(10*log 10) = 0.030103
// calculate K*20*log 20 = 0.030103*20*log 20 = 2.60206
// some more examples of simple algorithms:
for (int i = 0; i < n; ++i) { // n iterations
for (int j = 0; j < n; ++j) { // n iterations
a[i][j] = i * j; // n^2 multiplications (assignments)
}
}
// N*N, so O(N^2)
for (int i = 0; i < N; ++i) { // N iterations
for (int j = i; j < N; ++j) { // N, N-1 ,..., 1 iterations
a[i][j] = (i == j) ? 1:0;
}
}
// N + N-1 + ... + 1 = N(N+1)
// 1 + 2 + 3 + ... + N = (N+1) * N/2 = ------ = N^2/2 + N/2 = O(N^2)
// 2
// find duplicates
int a[] = { ... }; // unsorted array of integers
for (int i = 0; i < n; ++i) { // n iterations
for (int j = 0; j < n; ++j) { // n iterations
if ( i != j && a[i] == a[j] ) return true;
}
}
return false;
// best case 1
// worst case n^2
// average: ?????
// find duplicates
int a[] = { ... }; // unsorted array of integers
sort( a ); // assume O(NlogN)
for (int i = 0; i < n-1; ++i) { // n iterations
if ( a[i] == a[i+1] ) return true;
}
return false;
// best case NlogN = O(NlogN)
// worst case NlogN + N = O(NlogN)
// average: ?????
// printing dots (N,N/2,N/4,....,4,2,1 dots)
// ........
// ....
// ..
// .
int N = ...;
while( N>=1 ) {
for (int i = 0; i < N; ++i) {
std::cout << ".";
}
std::cout << std::endl;
}
// N + N/2 + N/4 + .... + 4 + 2 + 1
// Assume N = 2^n, then we need to calculate
// 2^0 + 2^1 + 2^2 + ... + 2^(n-1) + 2^n =
// this is geometric progression n+1
// b - 1
// FORMULA: b^0 + b^1 + b^2 + ... + b^(n-1) + b^n = ---------
// b - 1
// if b=2:
// 2^0 + 2^1 + 2^2 + ... + 2^(n-1) + 2^n = 2^(n+1) - 1
// since 2^(n+1) = 2 * 2^n = 2N
// N + N/2 + N/4 + .... + 4 + 2 + 1 = 2N -1
// Run time is linear: O(N)
// find values in an unsorted array M times, assume array size is N
// using brute-force find, we get M*N
//
// or first sort array and then use binary search:
// N*log(N) + M*log(N) = (M+N)*log(N)
//
// notice that comparison of M*N and (M+N)*log(N) depends on values of N and N
// M is much smaller than N:
// M*N = O(N) smaller
// (M+N)*log(N) = O( N*log(N) )
// M is comparable to N:
// M*N = O(N^2)
// (M+N)*log(N) = O( N*log(N) ) smaller