Sorting Algorithms, Templates, and Recursion Notes

Sorting Algorithms

  • Sorting is a common operation in programming, allowing data to be arranged in a specific order (e.g., numeric scores or alphabetical names).
  • Implementing sorting functions like bubble sort typically requires writing separate functions for different data types (e.g., strings vs. floats).
    • Bubble Sort Example:
      • void bubbleSort(String[] arr) {...}
      • void bubbleSort(float[] arr) {...}
  • The major overhead comes from having to replicate similar logic for each data type.

Templates in C++

  • To alleviate redundancy, use templates to create a generalized sorting function.
    • Template structure example:
      cpp template<typename T> void bubbleSort(T[] arr) {...}
    • T represents a placeholder for any data type (e.g., float, string, double, bool).
  • A templated function allows the same algorithm to handle various data types without rewriting the code.

Compile-Time vs Run-Time

  • Templates allow for compile-time type verification.
    • The compiler generates the specific code path for each type, reducing the need for run-time checks.
  • A comparison with virtual functions illustrates that templates resolve at compile time, while virtual functions resolve at run time.

File Type Polymorphism

  • Utilizing templates is a form of polymorphism: one function can operate on different data types efficiently.
  • Ensures that the template’s syntax remains consistent while the compiler handles the type-specific details.

STL Containers and Templates

  • The Standard Template Library (STL) includes templates like vector, which hold elements of any data type and expand as needed.
    • Example of creating a vector of different data types:
   vector<int> intVec;
   vector<float> floatVec;
  • Similar principles apply when creating custom classes that can handle multiple types using templates.
    • Define class:
      cpp template<typename T> class MyList {...};

Recursion Basics

  • Recursion is a method of solving problems where a function calls itself with adjusted parameters until a base case is met.
    • Example: Calculating factorials.
      • Factorial Function:
        cpp int factorial(int n) { if (n <= 1) return 1; else return n * factorial(n - 1); }
  • Recursion needs three components:
    • Recursive call (the function uses itself),
    • Base case (trivial case for which the answer is known),
    • Reduction operation (progress towards the base case).

Factors Influencing Recursion

  • Each recursion creates a new stack frame, which can lead to stack overflow if too deep without a base case (exceeding allowed calls).

Fibonacci Sequence Example

  • Recursive implementation of Fibonacci numbers:
    • Defined using smaller Fibonacci calculations.
      • Formula:

        F(n) = F(n-1) + F(n-2)
    • Base cases needed to avoid infinite recursion:
      • F(0)=0F(0) = 0 and F(1)=1F(1) = 1

The Towers of Hanoi

  • A classic problem suitable for recursive solutions
    • Move disks between rods according to specific rules to avoid larger disks over smaller disks.
    • Recursive logic breaks the problem into smaller equivalent problems, enabling solutions without manually computing all steps.

Summary

  • Templates streamline type-specific code for collection handling (like sorting) or data structure definition in programming, enhancing code reusability.
  • Recursion simplifies complex problems by reducing them into simpler instances, making it intuitive despite potential computational overhead.