Download as pdf or txt
Download as pdf or txt
You are on page 1of 35

LINEAR DATA STRUCTURE:

A linear data structure is a type of data structure where the elements are arranged in a sequential
manner, with each element having a unique predecessor and successor, except for the first and last
elements, which have only one adjacent element. In simpler terms, it's a structure where elements
are stored in a linear order, like a sequence.

Common examples of linear data structures include:

1. **Arrays:** Elements are stored in contiguous memory locations, and each element is accessed
using an index.

2. **Linked Lists:** Elements are stored as nodes, where each node contains a data element and a
reference (or pointer) to the next node in the sequence.

3. **Stacks:** Elements are added and removed according to the Last-In-First-Out (LIFO) principle.
The last element added is the first one to be removed.

4. **Queues:** Elements are added at the rear (enqueue) and removed from the front (dequeue)
according to the First-In-First-Out (FIFO) principle.

Linear data structures are straightforward to understand and implement, and they find applications
in various algorithms and scenarios where data needs to be processed in a sequential order.

ARRAY: REPRESENTATION OF ARRAYS,APPLICATION OF ARRAY:

In C++, an array is a collection of elements of the same data type, stored in contiguous memory
locations. Arrays allow you to store multiple values under a single name, making it easier to manage
and manipulate data.

REPRESENTATION OF ARRAY;

In C++, arrays are represented as a contiguous block of memory locations. Each element in the array
is stored at a specific memory address, and the elements are arranged sequentially. The
representation of an array in memory allows for efficient access to individual elements based on
their indices.

Here's an illustration of how an array is represented in memory:

```

---------------------------------------------------------

| Element 0 | Element 1 | Element 2 | ... | Element N-1 |

---------------------------------------------------------

```

In the above representation:

- Each box represents a memory location.


- The elements of the array are stored sequentially in memory.

- Each element occupies a fixed-size portion of memory, depending on its data type.

- The index of the first element is 0, and the index of the last element is N-1, where N is the size of
the array.

For example, consider the declaration of an array of integers in C++:

```cpp

int numbers[5] = {10, 20, 30, 40, 50};

```

In memory, it might be represented as follows (assuming each integer occupies 4 bytes):

```

--------------------------------------------------------

| 10 | 20 | 30 | 40 | 50 |

--------------------------------------------------------

```

In this representation:

- The array `numbers` contains 5 elements.

- Each element occupies 4 bytes of memory (assuming an integer is 4 bytes in size).

- The elements are stored sequentially in memory, with each element having its own memory
address.

This contiguous representation of arrays in memory allows for efficient random access to individual
elements using their indices, making arrays a fundamental data structure in C++ programming.

Here's a basic example of how to declare, initialize, and access elements of an array in C++:

```cpp

#include <iostream>

int main() {

// Declaration and initialization of an array of integers

int numbers[5] = {1, 2, 3, 4, 5};


// Accessing elements of the array

std::cout << "First element: " << numbers[0] << std::endl; // Output: 1

std::cout << "Second element: " << numbers[1] << std::endl; // Output: 2

// Modifying elements of the array

numbers[2] = 10;

std::cout << "Third element (after modification): " << numbers[2] << std::endl; // Output: 10

// Size of the array

int size = sizeof(numbers) / sizeof(numbers[0]);

std::cout << "Size of the array: " << size << std::endl; // Output: 5

return 0;

```

Key points about arrays in C++:

1. **Declaration:** You declare an array by specifying the data type of its elements and the number
of elements it can hold. For example: `int numbers[5];` declares an array of 5 integers.

2. **Initialization:** You can initialize the elements of the array at the time of declaration or later
using assignment statements. For example: `int numbers[5] = {1, 2, 3, 4, 5};` initializes the array with
the specified values.

3. **Accessing Elements:** Elements of an array are accessed using square brackets `[]` and
specifying the index of the element you want to access. Array indices start from 0. For example:
`numbers[0]` accesses the first element of the array.

4. **Size of Array:** You can determine the number of elements in an array using the `sizeof`
operator or by dividing the total size of the array by the size of one element. For example:
`sizeof(numbers) / sizeof(numbers[0])` calculates the size of the array.

Arrays in C++ are a fundamental data structure and are widely used in various applications, such as
storing collections of data, implementing algorithms, and working with multi-dimensional data.

APPLICATION OF ARRAY:
Arrays in C++ are fundamental data structures that find various applications in both C++
programming and Data Structures and Algorithms (DSA). Here are some common applications of
arrays in C++ and DSA:

1. **Storage of Data:** Arrays provide a convenient way to store collections of data of the same
type. They are used to store elements such as integers, characters, floating-point numbers, and
more.

2. **Implementation of Matrices:** Arrays are extensively used to represent matrices, especially in


numerical computations, graphics processing, and solving systems of linear equations.

3. **Traversal and Manipulation:** Arrays are used to traverse through a collection of elements and
perform operations on them. For example, searching for an element, sorting elements, and
modifying values.

4. **Dynamic Programming:** In DSA, arrays play a crucial role in dynamic programming algorithms.
Dynamic programming algorithms often involve storing intermediate results in arrays to avoid
redundant computations and improve efficiency.

5. **Searching Algorithms:** Arrays are used in searching algorithms like Linear Search and Binary
Search. These algorithms search for a particular element within an array and return its position or
indicate if the element is not found.

6. **Sorting Algorithms:** Arrays are extensively used in sorting algorithms like Bubble Sort,
Insertion Sort, Selection Sort, Merge Sort, and Quick Sort. These algorithms rearrange elements
within an array to arrange them in a specific order, such as ascending or descending.

7. **Hashing:** Arrays are used in hashing techniques to store key-value pairs efficiently. Hash
tables, which are widely used in associative arrays and dictionaries, often use arrays as their
underlying data structure.

8. **Stacks and Queues:** Arrays can be used to implement abstract data types like stacks and
queues. Stacks and queues have applications in various scenarios such as expression evaluation,
breadth-first search, depth-first search, and more.

9. **Sparse Arrays:** Arrays can also be used to represent sparse data structures efficiently. In
sparse arrays, elements that are mostly zero are represented in a compact form, saving memory
space.

10. **Multi-dimensional Arrays:** Arrays can be used to represent multi-dimensional data


structures, such as matrices, tensors, and grids, which are prevalent in fields like image processing,
scientific computing, and game development.

Overall, arrays are versatile and widely used in both C++ programming and DSA due to their
simplicity, efficiency, and effectiveness in various applications.

SINGLE DIMENSIONAL ARRAY, MULTI DIMENSIONAL ARRAY:

Sure, let's start with examples of single-dimensional and multi-dimensional arrays in C++, along with
a short note on each:
### Single-Dimensional Array:

```cpp

#include <iostream>

int main() {

// Declaration and initialization of a single-dimensional array

int numbers[5] = {1, 2, 3, 4, 5};

// Accessing elements of the array

std::cout << "First element: " << numbers[0] << std::endl; // Output: 1

std::cout << "Second element: " << numbers[1] << std::endl; // Output: 2

return 0;

```OUTPUT

First element: 1

Second element: 2

**Note on Single-Dimensional Arrays:**

Single-dimensional arrays in C++ are collections of elements of the same data type arranged
sequentially. They are useful for storing a list of items where each item can be accessed using its
index. Single-dimensional arrays are commonly used in various applications like storing lists of
numbers, characters, or other data types.

### Multi-Dimensional Array:

```cpp

#include <iostream>

int main() {

// Declaration and initialization of a multi-dimensional array


int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

// Accessing elements of the multi-dimensional array

std::cout << "Element at row 1, column 1: " << matrix[0][0] << std::endl; // Output: 1

std::cout << "Element at row 2, column 3: " << matrix[1][2] << std::endl; // Output: 6

return 0;

```OUTPUT

The output of the provided code snippet would be:

```

Element at row 1, column 1: 1

Element at row 2, column 3: 6

```

Explanation:

- The first `std::cout` statement prints the value of the element at row 1, column 1 of the `matrix`,
which is `1`.

- The second `std::cout` statement prints the value of the element at row 2, column 3 of the `matrix`,
which is `6`.

- Each value is printed on a new line due to the `std::endl` statement, which inserts a newline
character after printing the output.

**Note on Multi-Dimensional Arrays:**

Multi-dimensional arrays in C++ are arrays of arrays. They are used to represent tabular data,
matrices, and grids. The elements of a multi-dimensional array are accessed using multiple indices,
with each index representing a different dimension of the array. Multi-dimensional arrays are
commonly used in applications like image processing, scientific computing, and game development
where data is organized in a two-dimensional or higher-dimensional grid-like structure.

### Summary:

- **Single-Dimensional Arrays:** Used for storing a list of elements in a linear fashion, with each
element accessible via its index.
- **Multi-Dimensional Arrays:** Used for representing tabular data, matrices, and grids, with
elements accessible via multiple indices corresponding to different dimensions of the array.

Both single-dimensional and multi-dimensional arrays are fundamental data structures in C++ and
are widely used in various applications for organizing and manipulating data efficiently.

SPARSE MATRIX

In C++, a sparse matrix is a matrix where the majority of its elements are zero. Sparse
matrices are common in various applications, such as scientific computing, image processing,
and network analysis, where the matrices are large and most elements are zero.

SPARSE MATRIX REPRESENTATION;

Sure, let's implement a sparse matrix representation in C++ using the Compressed Sparse Row (CSR)
format, along with an explanation of the code.

```cpp

#include <iostream>

#include <vector>

struct CSRMatrix {

std::vector<int> values; // Non-zero values of the matrix

std::vector<int> columns; // Column indices of non-zero values

std::vector<int> rowIndices; // Starting index of each row in values and columns arrays

};

void printMatrix(const CSRMatrix& matrix) {

int row = 0;

for (int i = 0; i < matrix.values.size(); ++i) {

while (i >= matrix.rowIndices[row + 1]) {

row++;

std::cout << std::endl; // Move to next row

std::cout << matrix.values[i] << " "; // Print value

std::cout << std::endl;


}

int main() {

// Example sparse matrix: 3x3 matrix with non-zero elements (1, 2), (2, 1), and (2, 2)

CSRMatrix matrix;

matrix.values = {1, 2, 3}; // Non-zero values

matrix.columns = {0, 1, 1}; // Column indices

matrix.rowIndices = {0, 2, 3}; // Starting index of each row

// Print the sparse matrix

std::cout << "Sparse Matrix (CSR Representation):" << std::endl;

printMatrix(matrix);

return 0;

```

**Explanation:**

- In this code, we define a struct `CSRMatrix` to represent a sparse matrix in the Compressed Sparse
Row (CSR) format.

- The `values` vector stores the non-zero elements of the matrix.

- The `columns` vector stores the column indices of the non-zero elements.

- The `rowIndices` vector stores the starting index of each row in the `values` and `columns` arrays.

- We define a `printMatrix` function to print the sparse matrix using the CSR representation.

- In the `main` function, we initialize an example sparse matrix with non-zero elements at positions
(0, 0), (1, 1), and (2, 2).

- Finally, we print the sparse matrix using the `printMatrix` function.

This code demonstrates how to represent a sparse matrix using the CSR format in C++. In CSR
representation, we store only the non-zero elements of the matrix along with their row and column
indices. The code also includes a function to print the sparse matrix, which iterates through the
`values` vector and prints the elements row by row.
STACK:DEFINITION AND CONCEPTS

In C++ and Data Structures and Algorithms (DSA), a stack is a linear data structure that follows the
Last-In-First-Out (LIFO) principle. It means that the element inserted or pushed into the stack last will
be the first one to be removed or popped out. Stacks are widely used in various applications and
algorithms due to their simple and efficient nature.

Here are some key concepts and definitions related to stacks in C++ and DSA:

1. **Stack Operations:**

- **Push:** Insert an element onto the top of the stack.

- **Pop:** Remove and return the top element from the stack.

- **Peek or Top:** Return the top element of the stack without removing it.

- **Empty:** Check if the stack is empty.

- **Size:** Return the number of elements currently in the stack.

2. **Implementation:**

- Stacks can be implemented using arrays or linked lists.

- Array-based implementation: Fixed-size array or dynamic array (e.g., `std::vector` in C++).

- Linked list-based implementation: Each element of the stack is a node in a linked list.

3. **Applications:**

- Expression evaluation: Infix to postfix conversion, postfix expression evaluation.

- Function call stack: Storing function call information during recursion or nested function calls.

- Undo functionality: Storing the history of actions for undoing operations in applications.

- Backtracking algorithms: Storing the state of the search space during backtracking.

4. **Time Complexity:**

- Push, pop, peek, empty, and size operations typically have a time complexity of O(1) in most
implementations.

- The time complexity of these operations may vary slightly depending on the implementation
(array-based or linked list-based).

5. **Stack Overflow and Underflow:**

- Stack Overflow: Occurs when trying to push an element onto a full stack.

- Stack Underflow: Occurs when trying to pop an element from an empty stack.

6. **Standard Template Library (STL):**


- C++ provides a stack container adapter in the `<stack>` header, which implements the stack data
structure.

- The `std::stack` class in the STL provides all the essential stack operations and can be easily used
in C++ programs.

In summary, a stack is a fundamental data structure in C++ and DSA, characterized by its Last-In-First-
Out (LIFO) behavior. Understanding stack operations, implementations, applications, and
complexities is crucial for effectively using stacks in algorithm design and programming.

OPERATIONS ON STACKS:

Certainly! Let's implement basic stack operations in C++, including push, pop, peek, empty, and size,
along with explanations of the code.

```cpp

#include <iostream>

#include <stack>

int main() {

// Creating an empty stack

std::stack<int> myStack;

// Pushing elements onto the stack

myStack.push(10);

myStack.push(20);

myStack.push(30);

// Getting the size of the stack

std::cout << "Size of stack: " << myStack.size() << std::endl;

// Checking if the stack is empty

if (!myStack.empty()) {

// Peeking at the top element of the stack

std::cout << "Top element of stack: " << myStack.top() << std::endl;

// Popping elements from the stack

myStack.pop();

std::cout << "After popping, top element of stack: " << myStack.top() << std::endl;
}

return 0;

```

**Explanation:**

- **`#include <iostream>` and `#include <stack>`:** These lines include the necessary header files for
input/output operations and the stack container adapter in the C++ Standard Library (`

std::stack`).

- **`int main() { ... }`:** This is the main function where the execution of the program starts.

- **Creating an Empty Stack:**

```cpp

std::stack<int> myStack;

``` Here, we declare a stack named `myStack` capable of holding integer elements.

- **Pushing Elements onto the Stack:**

```cpp

myStack.push(10);

myStack.push(20);

myStack.push(30);

``` We push three integer values (10, 20, and 30) onto the stack using the `push` method.

- **Getting the Size of the Stack:**

```cpp

std::cout << "Size of stack: " << myStack.size() << std::endl;

```

We print the size of the stack using the `size` method, which returns the number of elements
currently in the stack.

- **Checking if the Stack is Empty:**

```cpp

if (!myStack.empty()) {

```
We check if the stack is not empty using the `empty` method. If the stack is not empty, we proceed
with the operations inside the if block.

- **Peeking at the Top Element of the Stack:**

```cpp

std::cout << "Top element of stack: " << myStack.top() << std::endl;

```

We print the top element of the stack using the `top` method, which returns a reference to the top
element without removing it from the stack.

- **Popping Elements from the Stack:**

```cpp

myStack.pop();

std::cout << "After popping, top element of stack: " << myStack.top() << std::endl;

```

We pop (remove) the top element from the stack using the `pop` method. After popping, we again
print the top element of the stack to verify the changes.

This code demonstrates the basic stack operations (push, pop, peek, empty, and size) using the stack
container adapter provided by the C++ Standard Library.

DIFFERENT TYPE OF EXPRESSION IN C++

In C++ and Data Structures and Algorithms (DSA), expressions can be represented in different
notations, such as infix, postfix, and prefix. Let's briefly discuss each notation:

1. **Infix Notation:**

- In infix notation, operators are placed between operands. For example, `2 + 3 * 4` is an infix
expression.

- Precedence and associativity rules determine the order of evaluation of infix expressions.

- Parentheses can be used to explicitly specify the order of evaluation.

2. **Postfix (Reverse Polish) Notation:**

- In postfix notation, also known as Reverse Polish Notation (RPN), operators are placed after their
operands. For example, `2 3 4 * +` is a postfix expression equivalent to `2 + 3 * 4` in infix notation.
- Postfix notation does not require parentheses or precedence rules, as the order of evaluation is
unambiguous.

3. **Prefix (Polish) Notation:**

- In prefix notation, also known as Polish Notation, operators are placed before their operands. For
example, `+ 2 * 3 4` is a prefix expression equivalent to `2 + 3 * 4` in infix notation.

- Prefix notation does not require parentheses or precedence rules, similar to postfix notation.

**Evaluation of Expressions:**

- Infix expressions are commonly evaluated using the shunting-yard algorithm or by converting them
to postfix or prefix notation first.

- Postfix and prefix expressions can be directly evaluated using a stack-based algorithm known as the
postfix evaluation algorithm or prefix evaluation algorithm, respectively.

- The stack-based approach makes evaluating postfix and prefix expressions more efficient compared
to infix expressions.

**Application of Expressions in DSA:**

- Expression evaluation: Evaluating arithmetic expressions, logical expressions, etc.

- Expression conversion: Converting between infix, postfix, and prefix notations.

- Parsing: Parsing and interpreting mathematical expressions in compilers and interpreters.

- Expression simplification: Simplifying algebraic expressions or Boolean expressions.

In summary, understanding different expression notations (infix, postfix, prefix) and their evaluation
algorithms is important in DSA for various applications such as expression evaluation, conversion,
parsing, and simplification.

APPLICATION OF STACK:

One common application of stacks in C++ and DSA is in evaluating postfix expressions. Let's
implement a postfix expression evaluator using a stack and explain the code along with its output.

```cpp

#include <iostream>

#include <stack>

#include <string>

// Function to evaluate a postfix expression


int evaluatePostfix(const std::string& expression) {

std::stack<int> stack;

for (char c : expression) {

if (isdigit(c)) {

stack.push(c - '0');

} else {

int operand2 = stack.top();

stack.pop();

int operand1 = stack.top();

stack.pop();

switch (c) {

case '+':

stack.push(operand1 + operand2);

break;

case '-':

stack.push(operand1 - operand2);

break;

case '*':

stack.push(operand1 * operand2);

break;

case '/':

stack.push(operand1 / operand2);

break;

return stack.top();

}
int main() {

// Example postfix expression: "53+82-*"

std::string postfixExpression = "53+82-*";

// Evaluate the postfix expression

int result = evaluatePostfix(postfixExpression);

// Print the result

std::cout << "Result of postfix expression '" << postfixExpression << "' is: " << result << std::endl;

return 0;

```

**Explanation:**

- **`#include <iostream>`, `#include <stack>`, `#include <string>`:** These lines include the
necessary header files for input/output operations, stack container adapter, and string manipulation
in the C++ Standard Library.

- **`int evaluatePostfix(const std::string& expression) { ... }`:** This function takes a postfix
expression as input and evaluates it using a stack. It returns the result of the evaluation.

- **`std::stack<int> stack;`:** We create an empty stack to store operands during the evaluation of
the postfix expression.

- **Evaluation Loop:**

- We iterate through each character in the postfix expression.

- If the character is a digit, we push it onto the stack.

- If the character is an operator (+, -, *, /), we pop the top two operands from the stack, perform the
operation, and push the result back onto the stack.

- **`int main() { ... }`:** This is the main function where the execution of the program starts.
- **Example Postfix Expression:**

```cpp

std::string postfixExpression = "53+82-*";

```

We define an example postfix expression "53+82-*".

- **Evaluate the Postfix Expression:**

```cpp

int result = evaluatePostfix(postfixExpression);

```

We call the `evaluatePostfix` function to evaluate the postfix expression and store the result.

- **Print the Result:**

```cpp

std::cout << "Result of postfix expression '" << postfixExpression << "' is: " << result << std::endl;

```

We print the result of the evaluation along with the original postfix expression.

**Output:**

```

Result of postfix expression '53+82-*' is: 3

```

This code demonstrates how to use a stack to evaluate a postfix expression in C++. The output shows
the result of evaluating the example postfix expression "53+82-*", which is 3.

POLISH EXPRESSION, REVERSE POLISH EXPRESSION AND THEIR COMPILATION IN C++ :

Certainly! Let's discuss Polish notation (Prefix) and Reverse Polish notation (Postfix) expressions along
with their evaluation in C++, and provide examples for each.

1. **Polish Expression (Prefix):**

- In Polish notation, operators precede their operands


- Operators are written before their operands, without any parentheses to indicate the order of
operations.

- Polish notation eliminates the need for parentheses and makes expressions unambiguous.

**Example:**

The infix expression `(3 + 4) * 5` in Polish notation becomes `* + 3 4 5`.

**Compilation in C++:**

To evaluate a Polish expression, we can use a stack-based algorithm to process operators and
operands sequentially.

2. **Reverse Polish Expression (Postfix):**

- In Reverse Polish notation, operators follow their operands.

- Operators are written after their operands, making the expression unambiguous and eliminating
the need for parentheses.

**Example:**

The infix expression `(3 + 4) * 5` in Reverse Polish notation becomes `3 4 + 5 *`.

**Compilation in C++:**

To evaluate a Reverse Polish expression, we can use a stack-based algorithm where we push
operands onto the stack and pop operands and perform operations when encountering an operator.

**Example C++ Code for Evaluation:**

```cpp

#include <iostream>

#include <stack>

#include <sstream>

#include <vector>

#include <string>

// Function to evaluate a Polish expression

int evaluatePolishExpression(const std::vector<std::string>& expression) {

std::stack<int> stack;

for (auto it = expression.rbegin(); it != expression.rend(); ++it) {

std::stringstream ss(*it);
if (isdigit((*it)[0])) {

int operand;

ss >> operand;

stack.push(operand);

} else {

int operand2 = stack.top();

stack.pop();

int operand1 = stack.top();

stack.pop();

char op = (*it)[0];

switch (op) {

case '+':

stack.push(operand1 + operand2);

break;

case '-':

stack.push(operand1 - operand2);

break;

case '*':

stack.push(operand1 * operand2);

break;

case '/':

stack.push(operand1 / operand2);

break;

return stack.top();

}
int main() {

// Example Reverse Polish expression: "3 4 + 5 *"

std::vector<std::string> rpnExpression = {"3", "4", "+", "5", "*"};

// Evaluate the Reverse Polish expression

int result = evaluatePolishExpression(rpnExpression);

// Print the result

std::cout << "Result of Reverse Polish expression '";

for (const auto& token : rpnExpression) {

std::cout << token << " ";

std::cout << "' is: " << result << std::endl;

return 0;

```

**Explanation:**

- The provided C++ code demonstrates how to evaluate a Reverse Polish expression using a stack-
based algorithm.

- We define a function `evaluatePolishExpression` that takes a vector of strings representing the


Reverse Polish expression as input.

- We use a stack to store operands and evaluate operators when encountered.

- The `main` function initializes an example Reverse Polish expression and evaluates it using the
`evaluatePolishExpression` function.

**Output:**

```

Result of Reverse Polish expression '3 4 + 5 *' is: 35

```
This code showcases the evaluation of a Reverse Polish expression in C++, demonstrating the
efficiency and simplicity of using Reverse Polish notation for expression evaluation.

RECURSION:

Recursion is a programming technique in which a function calls itself to solve smaller instances of the
same problem. It's a powerful tool used in algorithms and data structures to solve problems that can
be broken down into smaller, similar subproblems. Here's an example of recursion in C++ along with
its explanation:

```cpp

#include <iostream>

// Recursive function to calculate the factorial of a number

int factorial(int n) {

// Base case: factorial of 0 is 1

if (n == 0) {

return 1;

// Recursive case: factorial of n is n * factorial(n-1)

return n * factorial(n - 1);

int main() {

int num = 5; // Number for which factorial is to be calculated

std::cout << "Factorial of " << num << " is: " << factorial(num) << std::endl;

return 0;

```

**Explanation:**

- The `factorial` function is a recursive function that calculates the factorial of a non-negative integer
`n`.

- In the recursive case, if `n` is not zero, the function calls itself with the argument `n - 1` and
multiplies the result by `n`.
- The base case of the recursion is when `n` is zero, in which case the function returns 1.

- The `main` function calls the `factorial` function with a test value of `5` and prints the result.

**Output:**

```

Factorial of 5 is: 120

```

This example demonstrates how recursion can be used to calculate the factorial of a number. The
recursive function calls itself with a smaller argument until it reaches the base case, after which it
starts returning values to its previous calls, eventually returning the final result. Recursion is a
fundamental concept in programming and is used in various algorithms and data structures to solve
complex problems.

TOWER OF HANOI;

The Tower of Hanoi is a classic problem in computer science and mathematics. It involves three pegs
and a number of disks of different sizes which can be slid onto any peg. The puzzle starts with the
disks stacked in ascending order of size on one peg, with the smallest disk at the top. The objective is
to move the entire stack to another peg, following these rules:

1. Only one disk can be moved at a time.

2. Each move consists of taking the top disk from one stack and placing it onto another stack.

3. No disk may be placed on top of a smaller disk.

Here's the C++ code to solve the Tower of Hanoi problem:

```cpp

#include <iostream>

// Function to perform Tower of Hanoi

void towerOfHanoi(int n, char source, char auxiliary, char destination) {

if (n == 1) {

std::cout << "Move disk 1 from " << source << " to " << destination << std::endl;

return;

}
towerOfHanoi(n - 1, source, destination, auxiliary);

std::cout << "Move disk " << n << " from " << source << " to " << destination << std::endl;

towerOfHanoi(n - 1, auxiliary, source, destination);

int main() {

int numDisks = 3; // Number of disks

char source = 'A', auxiliary = 'B', destination = 'C'; // Pegs

std::cout << "Steps to solve Tower of Hanoi with " << numDisks << " disks:" << std::endl;

towerOfHanoi(numDisks, source, auxiliary, destination);

return 0;

```

**Explanation:**

- The function `towerOfHanoi` recursively solves the Tower of Hanoi problem.

- It takes four parameters: `n` (number of disks), `source` (the peg from which disks are initially
stacked), `auxiliary` (the auxiliary peg), and `destination` (the peg to which disks are moved).

- If there's only one disk (`n == 1`), it simply moves that disk from the source peg to the destination
peg.

- Otherwise, it recursively moves `n-1` disks from the source peg to the auxiliary peg, then moves the
remaining disk from the source peg to the destination peg, and finally recursively moves the `n-1`
disks from the auxiliary peg to the destination peg.

- In the `main` function, we define the number of disks (`numDisks`) and the pegs (`source`,
`auxiliary`, and `destination`), and then call the `towerOfHanoi` function to solve the problem.

**Output:**

```

Steps to solve Tower of Hanoi with 3 disks:

Move disk 1 from A to C

Move disk 2 from A to B


Move disk 1 from C to B

Move disk 3 from A to C

Move disk 1 from B to A

Move disk 2 from B to C

Move disk 1 from A to C

```

This code demonstrates how to solve the Tower of Hanoi problem using recursion in C++. Each step
of the solution is printed to show the movement of disks from one peg to another, adhering to the
rules of the puzzle.

QUEUE, REPRESENTATION OF QUEUE, OPERATION ON QUEUE,CIRCULAR QUEUE,PRIORITY


QUEUE,ARRAY REPRESENTATION OF PRIORITY QUEUE,DOUBLE ENDED QUEUE, APPLICATIONS OF
QUEUE;

Certainly! Let's cover the concepts of queues, circular queues, priority queues, and double-ended
queues (dequeues), along with their representations, operations, and applications in C++.

**Definition:**

- A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. It means that
the element inserted first will be the first one to be removed.

- Circular queue is a variation of the regular queue in which the last element is connected back to the
first element to form a circular structure.

- Priority queue is a type of queue where each element has an associated priority, and elements are
dequeued according to their priority.

- Double-ended queue (deque) is a generalized queue that supports insertion and deletion from both
the front and the rear ends.

**Representation of Queue:**

- Queues can be represented using arrays or linked lists.

- In array representation, we maintain two indices: `front` and `rear`, indicating the front and rear of
the queue, respectively.

- In linked list representation, each node contains a data element and a pointer to the next node.

**Operations on Queue:**

- **Enqueue:** Insert an element at the rear end of the queue.


- **Dequeue:** Remove and return the element from the front end of the queue.

- **Front:** Return the element at the front end of the queue without removing it.

- **Rear:** Return the element at the rear end of the queue without removing it.

- **IsEmpty:** Check if the queue is empty.

- **IsFull:** Check if the queue is full (applicable for bounded-size arrays).

**Circular Queue:**

- In a circular queue, after reaching the end of the array, the rear pointer wraps around to the
beginning of the array.

- This avoids wastage of space and allows efficient utilization of memory.

**Priority Queue:**

- Priority queues can be implemented using heaps or balanced binary search trees.

- In array representation, each element is stored along with its priority, and elements are dequeued
based on their priority.

**Double-Ended Queue (Deque):**

- Deques support insertion and deletion from both ends, making them versatile data structures.

- They can be implemented using arrays or linked lists.

**Applications of Queue:**

- **CPU Scheduling:** Queues are used to schedule processes in operating systems.

- **Breadth-First Search (BFS):** Queues are used to implement BFS algorithm for traversing graphs.

- **Printer Spooling:** Jobs waiting to be printed are queued.

- **Simulations:** Queues are used to model various real-world scenarios such as traffic flow,
customer service, etc.

**Example Code:**

Below is a simple implementation of a queue using arrays in C++:

```cpp

#include <iostream>
#define MAX_SIZE 5

class Queue {

private:

int arr[MAX_SIZE];

int front, rear;

public:

Queue() : front(-1), rear(-1) {}

bool isEmpty() {

return front == -1;

bool isFull() {

return (rear + 1) % MAX_SIZE == front;

void enqueue(int value) {

if (isFull()) {

std::cout << "Queue is full. Cannot enqueue." << std::endl;

return;

if (isEmpty()) {

front = rear = 0;

} else {

rear = (rear + 1) % MAX_SIZE;

arr[rear] = value;

}
int dequeue() {

if (isEmpty()) {

std::cout << "Queue is empty. Cannot dequeue." << std::endl;

return -1;

int value = arr[front];

if (front == rear) {

front = rear = -1;

} else {

front = (front + 1) % MAX_SIZE;

return value;

int frontElement() {

if (isEmpty()) {

std::cout << "Queue is empty. No front element." << std::endl;

return -1;

return arr[front];

int rearElement() {

if (isEmpty()) {

std::cout << "Queue is empty. No rear element." << std::endl;

return -1;

return arr[rear];

};
int main() {

Queue q;

q.enqueue(10);

q.enqueue(20);

q.enqueue(30);

std::cout << "Front element: " << q.frontElement() << std::endl;

std::cout << "Rear element: " << q.rearElement() << std::endl;

std::cout << "Dequeued element: " << q.dequeue() << std::endl;

std::cout << "Front element after dequeue: " << q.frontElement() << std::endl;

return 0;

```

This code provides a basic implementation of a queue using arrays in C++. It demonstrates the
operations of enqueue, dequeue, front, and rear elements of the queue.

ARRAT REPRESENTATION OF PRIORITY QUEUE:

In a priority queue, elements are stored based on their priority, and the element with the highest
priority is dequeued first. The array representation of a priority queue typically involves storing both
the elements and their associated priorities. Here's how you can implement an array-based priority
queue in C++:

```cpp

#include <iostream>

#include <algorithm> // For std::swap

#define MAX_SIZE 10

class PriorityQueue {

private:
int arr[MAX_SIZE]; // Array to store elements

int priorities[MAX_SIZE]; // Array to store priorities

int rear; // Index of the last element in the priority queue

public:

PriorityQueue() : rear(-1) {}

bool isEmpty() {

return rear == -1;

bool isFull() {

return rear == MAX_SIZE - 1;

void enqueue(int value, int priority) {

if (isFull()) {

std::cout << "Priority queue is full. Cannot enqueue." << std::endl;

return;

rear++;

arr[rear] = value;

priorities[rear] = priority;

// Rearrange elements based on priority

for (int i = rear; i > 0; i--) {

if (priorities[i] > priorities[i - 1]) {

std::swap(arr[i], arr[i - 1]);

std::swap(priorities[i], priorities[i - 1]);

} else {

break;

}
}

int dequeue() {

if (isEmpty()) {

std::cout << "Priority queue is empty. Cannot dequeue." << std::endl;

return -1;

int value = arr[rear];

rear--;

return value;

int frontElement() {

if (isEmpty()) {

std::cout << "Priority queue is empty. No front element." << std::endl;

return -1;

return arr[rear];

};

int main() {

PriorityQueue pq;

pq.enqueue(10, 2);

pq.enqueue(20, 1);

pq.enqueue(30, 3);

std::cout << "Front element: " << pq.frontElement() << std::endl;

std::cout << "Dequeued element: " << pq.dequeue() << std::endl;

std::cout << "Front element after dequeue: " << pq.frontElement() << std::endl;
return 0;

```

In this implementation:

- We use two arrays `arr` and `priorities` to store the elements and their associated priorities,
respectively.

- Elements are enqueued with their priorities, and after each insertion, elements are rearranged
based on their priorities to maintain the priority order.

- The element with the highest priority is dequeued first.

- The `enqueue` operation inserts an element into the priority queue with the given priority.

- The `dequeue` operation removes and returns the element with the highest priority from the
priority queue.

- The `frontElement` operation returns the element with the highest priority without removing it
from the priority queue.

This array-based priority queue implementation allows efficient insertion and removal of elements
based on their priorities.

LINKED LIST, SINGLE LINKED LIST, DOUBLE LINKED LIST, CIRCULAR LINKED LIST, LINKED
IMPLEMENTATION OF STACK , LINKED IMPLEMENTATION OF QUEUE, APPLICATION OF LINKED LIST

Certainly! Let's explore linked lists, singly linked lists, doubly linked lists, circular linked lists, and their
implementations as stacks and queues in C++. We'll also discuss their applications and provide code
examples with explanations and outputs.

**Linked List:**

- A linked list is a linear data structure consisting of a sequence of elements, called nodes, where
each node contains a data field and a reference (link) to the next node in the sequence.

- Linked lists provide dynamic memory allocation and efficient insertion and deletion operations.

**Singly Linked List:**

- In a singly linked list, each node contains a single link field pointing to the next node in the
sequence.

- Traversal in a singly linked list is only possible in the forward direction.


**Doubly Linked List:**

- In a doubly linked list, each node contains two link fields: one pointing to the next node and one
pointing to the previous node in the sequence.

- Traversal in a doubly linked list can be done in both forward and backward directions.

**Circular Linked List:**

- In a circular linked list, the last node of the list points back to the first node, forming a circular
structure.

- Circular linked lists can be singly or doubly linked.

**Linked Implementation of Stack:**

- A stack can be implemented using a singly linked list.

- Push operation inserts elements at the beginning of the linked list (head).

- Pop operation removes and returns the first element of the linked list (head).

**Linked Implementation of Queue:**

- A queue can be implemented using a singly linked list.

- Enqueue operation inserts elements at the end of the linked list.

- Dequeue operation removes and returns the first element of the linked list.

**Applications of Linked Lists:**

- Dynamic memory allocation (e.g., memory management in languages like C/C++).

- Implementing other data structures like stacks, queues, and hash tables.

- Applications involving frequent insertion and deletion operations.

**Example Code:**

Below is a simple implementation of a singly linked list-based stack and queue in C++:

```cpp

#include <iostream>

// Node structure for linked list


struct Node {

int data;

Node* next;

Node(int value) : data(value), next(nullptr) {}

};

// Stack implemented using linked list

class Stack {

private:

Node* top;

public:

Stack() : top(nullptr) {}

bool isEmpty() {

return top == nullptr;

void push(int value) {

Node* newNode = new Node(value);

newNode->next = top;

top = newNode;

int pop() {

if (isEmpty()) {

std::cout << "Stack is empty. Cannot pop." << std::endl;

return -1;

int value = top->data;

Node* temp = top;


top = top->next;

delete temp;

return value;

};

// Queue implemented using linked list

class Queue {

private:

Node* front;

Node* rear;

public:

Queue() : front(nullptr), rear(nullptr) {}

bool isEmpty() {

return front == nullptr;

void enqueue(int value) {

Node* newNode = new Node(value);

if (isEmpty()) {

front = rear = newNode;

} else {

rear->next = newNode;

rear = newNode;

int dequeue() {

if (isEmpty()) {
std::cout << "Queue is empty. Cannot dequeue." << std::endl;

return -1;

int value = front->data;

Node* temp = front;

front = front->next;

if (front == nullptr) {

rear = nullptr;

delete temp;

return value;

};

int main() {

Stack stack;

stack.push(10);

stack.push(20);

stack.push(30);

std::cout << "Popped element: " << stack.pop() << std::endl;

Queue queue;

queue.enqueue(10);

queue.enqueue(20);

queue.enqueue(30);

std::cout << "Dequeued element: " << queue.dequeue() << std::endl;

return 0;

```
**Explanation:**

- The code implements a singly linked list-based stack and queue.

- For the stack, the push operation inserts elements at the beginning of the linked list, and the pop
operation removes and returns the first element.

- For the queue, the enqueue operation inserts elements at the end of the linked list, and the
dequeue operation removes and returns the first element.

- The `isEmpty` function is used to check if the stack or queue is empty before performing pop or
dequeue operations.

**Output:**

```

Popped element: 30

Dequeued element: 10

```

This code demonstrates the implementation of a singly linked list-based stack and queue in C++,
along with sample output after performing push/pop and enqueue/dequeue operations. Linked lists
provide efficient dynamic memory allocation and are widely used in various applications.

You might also like