ScholarQuill logoScholarQuillUniversity Notes
My Semester
Explore Notes
Past Papers12 New
Video CoursesNew
Search
Settings
Study Tools
GPA/CGPA Calculator
Schedule & To-Do
Student Portal
Contact
Contact
ScholarQuill logo
My Semester
Explore Notes
Past Papers12 New
Video CoursesNew
Search
Settings
GPA/CGPA Calculator
Schedule & To-Do
Student Portal
Contact
ScholarQuill logoScholarQuillUniversity Notes
Study PortalCC-213Complexity Analysis
Ctrl + K
Login
Explore
Search
Semester
Papers
CGPA
    CC-213

    Data Structures & Algorithms

    Progress0 / 37 done
    Topics37
    1Abstract Data Types2Complexity Analysis3Big Oh Notation4Stacks (Linked Lists and Array Implementations)5Recursion and analyzing recursive algorithms6Divide and Conquer Algorithms7Sorting Algorithms8Selection Sort9Insertion Sort10Merge Sort11Quick Sort12Bubble Sort13Heap Sort14Shell Sort15Radix Sort16Bucket Sort17Queue18Dequeuer19Priority Queues (linked and array implementations of queues)20Linked List and Its Various Types21Sorted Linked List22Searching an Unsorted Array23Binary Search for Sorted Arrays24Hashing and Indexing25Open Addressing and Chaining26Trees and Tree Traversals27Binary Search Trees28Heaps29M-Way Trees30Balanced Trees31Graphs32Breadth-First Traversal33Depth-First Traversal34Topological Order35Shortest Path36Adjacency Matrix and Adjacency List Implementations37Memory Management and Garbage Collection
    7 min read
    Topic 2 of 37
    Topic Study Note Illustration
    02

    Complexity Analysis

    Complexity analysis in computer science is the study of how the performance of an algorithm or a data structure grows with the size of the input. It...

    Complexity Analysis

    Complexity analysis in computer science is the study of how the performance of an algorithm or a data structure grows with the size of the input. It helps us understand how efficient an algorithm is in terms of time (how fast it runs) and space (how much memory it uses).

    There are two main types of complexity:

    1. Time Complexity: How the execution time of an algorithm grows as the input size increases.
    2. Space Complexity: How the memory usage of an algorithm grows as the input size increases.

    Time Complexity

    Time complexity tells us how many operations an algorithm needs to perform relative to the size of the input. It’s often expressed using Big O notation, which describes the worst-case scenario of the algorithm.

    Big O Notation

    Big O notation helps to classify algorithms based on their time or space requirements. Here are some common Big O notations:

    1. O(1) – Constant Time: The algorithm takes the same amount of time regardless of the input size.

      • Example: Accessing an element in an array by its index.
      • C++ Example:
        int arr[5] = {1, 2, 3, 4, 5};
        int element = arr[2];  // O(1)
        
    2. O(log n) – Logarithmic Time: The algorithm's time increases logarithmically as the input size increases. This usually happens in algorithms that divide the input into smaller parts.

      • Example: Binary Search.
      • C++ Example:
        int binarySearch(int arr[], int size, int target) {
            int low = 0, high = size - 1;
            while (low <= high) {
                int mid = (low + high) / 2;
                if (arr[mid] == target) return mid;
                else if (arr[mid] < target) low = mid + 1;
                else high = mid - 1;
            }
            return -1;
        }
        // O(log n)
        
    3. O(n) – Linear Time: The time grows linearly with the input size. If the input doubles, the execution time doubles.

      • Example: Traversing an array.
      • C++ Example:
        void printArray(int arr[], int size) {
            for (int i = 0; i < size; i++) {
                cout << arr[i] << " ";
            }
        }
        // O(n)
        
    4. O(n log n) – Linearithmic Time: Often occurs in algorithms that involve both dividing the input (like O(log n)) and then processing each part (like O(n)).

      • Example: Merge Sort, Quick Sort.
      • C++ Example (Merge Sort):
        void merge(int arr[], int l, int m, int r) {
            // Merging logic
        }
        
        void mergeSort(int arr[], int l, int r) {
            if (l < r) {
                int m = l + (r - l) / 2;
                mergeSort(arr, l, m);
                mergeSort(arr, m + 1, r);
                merge(arr, l, m, r);
            }
        }
        // O(n log n)
        
    5. O(n²) – Quadratic Time: The time increases quadratically with the input size. If the input size doubles, the time quadruples. This usually happens in algorithms that have nested loops.

      • Example: Bubble Sort, Selection Sort.
      • C++ Example (Bubble Sort):
        void bubbleSort(int arr[], int n) {
            for (int i = 0; i < n - 1; i++) {
                for (int j = 0; j < n - i - 1; j++) {
                    if (arr[j] > arr[j + 1]) {
                        swap(arr[j], arr[j + 1]);
                    }
                }
            }
        }
        // O(n²)
        
    6. O(2ⁿ) – Exponential Time: The time doubles with each addition to the input size. This is typical in algorithms that solve problems by recursively exploring all possible solutions.

      • Example: Solving the Tower of Hanoi problem.
      • C++ Example:
        void towerOfHanoi(int n, char from_rod, char to_rod, char aux_rod) {
            if (n == 1) {
                cout << "Move disk 1 from rod " << from_rod << " to rod " << to_rod << endl;
                return;
            }
            towerOfHanoi(n - 1, from_rod, aux_rod, to_rod);
            cout << "Move disk " << n << " from rod " << from_rod << " to rod " << to_rod << endl;
            towerOfHanoi(n - 1, aux_rod, to_rod, from_rod);
        }
        // O(2ⁿ)
        
    7. O(n!) – Factorial Time: The time increases dramatically as the input size increases. This is typical in brute-force solutions that try every possible configuration.

      • Example: Solving the Traveling Salesman Problem with a brute-force approach.

    Space Complexity

    Space complexity measures how much memory an algorithm uses, relative to the size of the input. Just like time complexity, space complexity is expressed in Big O notation.

    For example, if you're using an extra array to store results, your space complexity might increase. Here are some typical space complexities:

    1. O(1) – Constant space: The algorithm uses the same amount of memory, regardless of the input size.

      • Example: Swapping two numbers in-place.
    2. O(n) – Linear space: The memory usage grows linearly with the input size.

      • Example: Storing an array of size n.

    Best Case, Worst Case, and Average Case

    When analyzing an algorithm, there are different scenarios:

    • Best Case: The minimum amount of time the algorithm will take (optimistic scenario).

      • Example: In a sorted array, the best case for linear search is finding the element in the first position, which takes O(1) time.
    • Worst Case: The maximum amount of time the algorithm will take (pessimistic scenario).

      • Example: In linear search, the worst case is when the element is at the end of the array or not present, taking O(n) time.
    • Average Case: The expected time the algorithm will take, considering all possible inputs. This can be harder to calculate but gives a realistic picture of performance.

    Example: Linear Search Complexity Analysis

    Let's consider linear search in an unsorted array.

    • Time Complexity:

      • Best Case: O(1) – If the element is found at the first index.
      • Worst Case: O(n) – If the element is not found or at the last index.
      • Average Case: O(n) – On average, the algorithm will look through half the elements.
    • Space Complexity: O(1) – No extra space is used apart from a few variables for indexing and comparisons.

    Why is Complexity Analysis Important?

    1. Efficiency: It helps in selecting the best algorithm for the task. If you have a large dataset, you want an algorithm that runs efficiently with low time complexity.

    2. Scalability: Complexity analysis tells you how the algorithm will behave as the input size grows. This is especially important when dealing with big data.

    3. Performance: Understanding the complexity helps you optimize both time and space usage, which is crucial for resource-constrained environments like embedded systems or mobile devices.

    Conclusion

    Complexity analysis helps us measure the efficiency of algorithms by focusing on how they perform with increasing input size. By using Big O notation, we can evaluate the time and space complexity, allowing us to make better choices when designing and implementing algorithms.

    ← Previous topic 1
    Abstract Data Types
    Next topic 3 →
    Big Oh Notation

    Past Papers

    Open this section to view and download past papers

    Click on Show Past Papers to load available exam papers.

    Reading Progress
    0%
    7mremaining
    1.1kwords
    Intermediatelevel
    On This Page

    No headings found

    Study Toolkit

    Subject Portal

    Data Structures & Algorithms