Consider for example a "unique string" algorithm, where you want to check if a string contains all unique characters. A naive approach to the problem, which does not use extra data structures, is to go through the string, iterating each letter against the entire string searching for a match. This approach is O(n^2).
int strunique_naive(const char *str) { char *iter, *tmp; for (iter = (char *)str; *iter != '\0'; ++iter) for (tmp = (char *)str; *tmp != '\0'; ++tmp) if (*tmp == *iter) return 0; return 1; }
Now consider a better approach to the problem. We can optimize the algorithm by adding an offset for the iterating over the string part, since for example in a short string there is no reason to test the last character with the first character as the first character already performed that test during its loop-through.
int strunique_better(const char *str) { size_t offset = 0; /* offset at 0 */ char *iter, *tmp; for (iter = (char *)str; *iter != '\0'; ++iter, ++offset) for (tmp = (char *)str + offset; *tmp != '\0'; ++tmp) if (*tmp == *iter) return 0; return 1; } int strunique_best(const char *str) { size_t offset = 1; /* pre-emptively shift offset up */ /* repeat code above */ }
When we calculate the number of loops for the worst-case scenario (i.e. a string that is unique) for the naive algorithm, we get n^2 loops. The better algorithm is done in (n^2 + n) / 2, and the best is n * (n - 1) / 2 loops. The following table shows the differences:
# of Loops on Worst Case
strunique_naive | strunique_better | strunique_best | |
---|---|---|---|
1 character | 1 | 1 | 0 |
2 characters | 4 | 3 | 1 |
3 characters | 9 | 6 | 3 |
5 characters | 25 | 15 | 10 |
10 characters | 100 | 55 | 45 |
100 characters | 10,000 | 5,050 | 4,950 |
So why can you not trust Big-O complexity for actual performance? All 3 algorithms are actually O(n^2)! The better and best algorithms just have an improved actual performance equation.
Algorithm Benchmarks
strunique_naive | strunique_better | strunique_best | |
---|---|---|---|
Big-O Complexity | O(n^2) | O(n^2) | O(n^2) |
Actual Performance | n^2 | (n^2 + n) / 2 | n * (n - 1) / 2 |
No comments :
Post a Comment