Terminology:
Formal definition — "if there exists positive constants c and b such that f(n) ≤ cg(n) holds for all n > b, then f(n) is O(g(n))"
Eg.
Big O — upper limit (worst case) f(n) ≤ cg(n) Big Θ — average range f(n) ≥ cg(n) Big Ω — lower limit (best case) c'g(b) ≤ f(n) ≤ c''g(n) The worst case time-complexity is generally the most important to discuss
Polynomials: for f(n) with degree d, f(n) is O(nᵈ)
For finding the worst case in recursive algorithms, we must understand the logic and work out how many steps are taken to reach the base case
Complexity classes
Generate and test algorithms: Useful when it is simple to generate new states and test whether they are a solution. This guarantees we either find a solution, or prove none exist. Eg. Checking primality by generating 2 to n-1 numbers and testing them
Big-O is not about the exact number of operations. It's about how the number of operations changes with respect to input size. A function with O(1) complexity (constant time) could take 0.000001 seconds to execute or two weeks to execute.
Time-complexity for different operations on common data structures:
Examples: O(1)
void swap(int a[], int i, int j) {
int tmp = a[i]; // O(1)
a[i] = a[j]; // O(1)
a[j] = tmp; // O(1)
} // Total: O(1)
O(n)
for (int i = 0; i < n; i++) {
// Some O(1) statements
} // Total: O(n)
O(n²)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// Some O(1) statements
}
} // Total: O(n²), basically just counting how many times the innermost
// statements get executed, relative to n
O(logn)
for (int i = 0; i < n; i *= 2) {
// Some O(1) statements
} // Total: O(log₂n)
// Eg. for n = 100, the loop will execute log₂(100) times,
// which is 6 or 7 times
Set ADT example: A typical abstract set data structure may support the declare the following functions in its header file:
Set newSet();
void freeSet(Set s);
void displaySet(Set s);
void setInsert(Set s, int data);
void setRemove(Set s, int target);
bool setIsMember(Set s, int target);
Set setUnion(Set s, Set t);
Set setIntersection(Set s, Set t);
int setCardinality(Set s);
Time-complexities for a set implementation using various underlying data structures:
As the person implementing an abstract data type for other users, after you decide what functions you want to supply, you have to go through each possible implementation and compare the set of time-complexities for each implementation. You choose the appropriate implementation based on which functions are most important to the specifications.