My Notes!!
My Notes!!
RECURSIONS:
Recursion in C++ refers to the technique where a function calls itself in order to solve a
problem or perform a task. In a recursive function, the function continues to call itself with
modified arguments until a base case is reached, at which point the recursion stops and the
function returns values that can be used to compute the final result.
1. Base Case: This is the condition that terminates the recursion. Without a base case,
the recursion would continue indefinitely. The base case allows the function to return
a result without making further recursive calls.
2. Recursive Case: This is the part of the function where it calls itself with modified
arguments. The recursive case typically reduces the problem size or moves closer to
the base case.
Here's a simple example of a recursive function in C++ that calculates the factorial of a
number:
#include <iostream>
int factorial(int n) {
// Base case
if (n == 0 ) { return 1 ; } // Recursive case else { return n * factorial (n - 1 ); } } int main() { int num =
5 ; int result = factorial (num); std::cout << "Factorial of " << num << " is " << result << std::endl; return
0; }
In this example, the factorial function calculates the factorial of a number by calling itself
with a smaller number in each recursive step until it reaches the base case (when n is 0).
When the base case is reached, the recursion stops, and the results are combined as the
recursive calls are unwound.
Recursion is a powerful tool in C++ and can be used to solve problems that have a recursive
structure, such as tree traversal, mathematical calculations, and more. However, it's important
to ensure that there's a proper base case and that the problem size decreases with each
recursive call to avoid infinite recursion.
1. Function Templates:
• Function templates allow you to define a template function that can work with
multiple data types. You specify the data type as a parameter when calling the
function.
• Function templates are defined using the template keyword followed by a
list of template parameters enclosed in angle brackets (<>).
• For example:
code
template < typename T> T add(T a, T b) { return a + b; }
You can use this function template with various data types like int , double , or even
custom types.
2. Class Templates:
• Class templates are similar to function templates, but they allow you to create
generic classes.
• Class templates are defined using the template keyword followed by a list of
template parameters enclosed in angle brackets (<>), just like function
templates.
• For example:
code
template < typename T> class Stack { public : // Implement a stack data structure that works
with type T void push(T value) ; T pop() ; };
You can then create instances of the Stack class for different data types, such as int ,
double , or custom types.
When you use a template, the C++ compiler generates code for specific data types at compile
time. This is known as template specialization. Template specialization allows you to write
code that is both generic and efficient because it's customized for the specific data types you
use.
cppCopy code
int main() { int x = 5 , y = 10 ; double a = 3.5 , b = 2.7 ; int sum_int = add (x, y); // Calls add<int>(x, y)
double sum_double = add (a, b); // Calls add<double>(a, b) return 0 ; }
Templates are an essential feature in C++ for creating flexible and reusable code, and they
are widely used in the standard library to provide generic containers (like std::vector and
std::map ) and algorithms (like std::sort ).
Pointers require careful management to avoid issues like memory leaks, dangling pointers,
and accessing invalid memory locations. Smart pointers, introduced in C++11, help with
memory management by automatically deallocating memory when it's no longer needed,
reducing the risk of common pointer-related problems.
cppCopy code
#include <iostream> int main() { int x = 42 ; // Declare an integer variable int * ptr = &x; // Declare a
pointer and initialize it with the address of 'x' // Access the value using the pointer and dereference
operator std::cout << "Value of x: " << x << std::endl; std::cout << "Value pointed to by ptr: " << *ptr <<
std::endl; // Pointer arithmetic int y = 10 ; int * ptr2 = &y; std::cout << "Value of y: " << y << std::endl;
// Increment the pointer, moving it to the next int in memory ptr2++; std::cout << "Value pointed to by
ptr2 after increment: " << *ptr2 << std::endl; // Decrement the pointer ptr2--; std::cout << "Value
pointed to by ptr2 after decrement: " << *ptr2 << std::endl; // Demonstrating NULL pointers int *
nullPtr = nullptr ; // Declare a NULL pointer if (nullPtr == nullptr ) { std::cout << "nullPtr is a NULL
pointer." << std::endl; } // Changing the value using the pointer *ptr = 100 ; // Modify the value of 'x'
using the pointer std::cout << "Updated value of x: " << x << std::endl; return 0 ; }
In this example:
1. We declare an integer variable x and a pointer ptr that is initialized with the address
of x .
2. We access the value of x using both x and *ptr .
3. We declare another integer variable y and a pointer ptr2 . We demonstrate pointer
arithmetic by incrementing and decrementing ptr2 .
4. We declare a NULL pointer nullPtr and check if it's a NULL pointer using the
nullptr keyword.
5. We use the pointer to modify the value of x .
Keep in mind that pointers require careful handling, and improper use can lead to issues like
memory corruption and segmentation faults. Always make sure you are working with valid
memory locations and consider using smart pointers and standard containers whenever
possible to manage memory more safely.
In C++, templates and classes serve different purposes, but you can achieve some level of
interchangeability or conversion between them in certain situations. Here's how you can
convert templates to classes and vice versa:
Remember that the choice between a template and a concrete class depends on your specific
requirements. Templates are best suited when you want to create generic classes or functions
that work with multiple data types, whereas concrete classes are used for specific data types
or when you don't need the flexibility of generics.
IMPLEMENTATION OF ADT’S
// Function prototypes
MyADT* createMyADT();
void destroyMyADT(MyADT* adt);
void insertData(MyADT* adt, int data);
int retrieveData(MyADT* adt);
#endif
ACCESSING ADT
struct MyADT {
// Define the internal representation of the data structure
};
MyADT* createMyADT() {
// Implementation of create function
}