# ๐Ÿ“˜ Algorithm Complexity Cheat Sheet A visual and practical overview for understanding algorithmic complexity (Big O notation). Prepared for the course *"Algorithms and Data Structures in C# (.NET)"* ๐Ÿ‘จโ€๐Ÿซ **Dr. Stoyan Cheresharov**, Plovdiv University โ€œPaisii Hilendarskiโ€ --- ## ๐Ÿง  What Is Big O Notation? **Big O notation** describes how the runtime or memory usage of an algorithm grows as the **input size (n)** increases. The **O** stands for *Order* โ€” it represents the *upper bound* (worst-case growth rate). --- ## ๐Ÿ”ข Why Do We Use It? Big O lets us compare algorithms **independently of hardware or language**. It shows how fast an algorithmโ€™s runtime grows when the problem size increases. --- ## โš™๏ธ Common Complexities | Big-O | Name | Example | Meaning | |--------|------|----------|---------| | **O(1)** | Constant | Access array element | Same time regardless of input size | | **O(log n)** | Logarithmic | Binary Search | Work halves each step | | **O(n)** | Linear | Simple loop | Work grows directly with input size | | **O(n log n)** | Quasi-linear | Merge Sort | Typical for efficient sorting | | **O(nยฒ)** | Quadratic | Nested loops | Slower as size doubles | | **O(2โฟ)** | Exponential | Recursive Fibonacci | Work doubles each time n increases | | **O(n!)** | Factorial | Permutations | Tests all possible orderings | --- ## ๐Ÿ’ป C# Examples ### ๐ŸŸฉ Constant Time โ€“ O(1) ```csharp int x = arr[0]; // Accessing by index ``` ### ๐ŸŸฆ Linear Time โ€“ O(n) ```csharp for (int i = 0; i < arr.Length; i++) Console.WriteLine(arr[i]); ``` ### ๐ŸŸฅ Quadratic Time โ€“ O(nยฒ) ```csharp for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) sum += i * j; ``` ### ๐ŸŸจ Logarithmic Time โ€“ O(log n) ```csharp int BinarySearch(int[] arr, int x) { int low = 0, high = arr.Length - 1; while (low <= high) { int mid = (low + high) / 2; if (arr[mid] == x) return mid; if (arr[mid] < x) low = mid + 1; else high = mid - 1; } return -1; } ``` --- ## ๐Ÿ“ˆ Growth Visualization (Conceptual) ```text Runtime growth vs Input size n โ”‚ โ”‚ O(nยฒ) โ”‚ O(n log n) โ”‚ O(n) โ”‚ O(log n) โ”‚ O(1) โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ n ``` **Interpretation:** - **O(1)** โ†’ Instant (constant work) - **O(log n)** โ†’ Slower growth (binary search) - **O(n)** โ†’ Linear growth (single loop) - **O(nยฒ)** โ†’ Rapid growth (nested loops) --- ## ๐Ÿงฎ How Complexities Are Calculated | Type | Example | Step Count | Result | |------|----------|-------------|---------| | Constant | `arr[0]` | 1 | O(1) | | Linear | `for (i < n)` | n | O(n) | | Quadratic | `for(i Big O is not about *exact speed*, itโ€™s about *how performance scales*. **In short:** - Use **O(1)** when possible. - Aim for **O(n)** or **O(n log n)** in practical algorithms. - Avoid **O(nยฒ)** and worse in large data sets. --- ๐Ÿ“— **Prepared by:** Dr. Stoyan Cheresharov ๐Ÿ“ Plovdiv University โ€œPaisii Hilendarskiโ€ ๐Ÿ–ฅ๏ธ Course: *Algorithms and Data Structures in C# (.NET)* ---