Professional Documents
Culture Documents
UNIT 02 - LINEAR DATA STRUCTURE (C++)
UNIT 02 - LINEAR DATA STRUCTURE (C++)
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.
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.
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.
```
---------------------------------------------------------
---------------------------------------------------------
```
- 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.
```cpp
```
```
--------------------------------------------------------
| 10 | 20 | 30 | 40 | 50 |
--------------------------------------------------------
```
In this representation:
- 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() {
std::cout << "First element: " << numbers[0] << std::endl; // Output: 1
std::cout << "Second element: " << numbers[1] << std::endl; // Output: 2
numbers[2] = 10;
std::cout << "Third element (after modification): " << numbers[2] << std::endl; // Output: 10
std::cout << "Size of the array: " << size << std::endl; // Output: 5
return 0;
```
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.
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.
Overall, arrays are versatile and widely used in both C++ programming and DSA due to their
simplicity, efficiency, and effectiveness in various applications.
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() {
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
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.
```cpp
#include <iostream>
int main() {
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
```
```
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.
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.
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> rowIndices; // Starting index of each row in values and columns arrays
};
int row = 0;
row++;
int main() {
// Example sparse matrix: 3x3 matrix with non-zero elements (1, 2), (2, 1), and (2, 2)
CSRMatrix matrix;
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 `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).
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:**
- **Pop:** Remove and return the top element from the stack.
- **Peek or Top:** Return the top element of the stack without removing it.
2. **Implementation:**
- Linked list-based implementation: Each element of the stack is a node in a linked list.
3. **Applications:**
- 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).
- 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.
- 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() {
std::stack<int> myStack;
myStack.push(10);
myStack.push(20);
myStack.push(30);
if (!myStack.empty()) {
std::cout << "Top element of stack: " << myStack.top() << std::endl;
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.
```cpp
std::stack<int> myStack;
``` Here, we declare a stack named `myStack` capable of holding integer elements.
```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.
```cpp
```
We print the size of the stack using the `size` method, which returns the number of elements
currently in the stack.
```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.
```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.
```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.
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.
- 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.
- 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.
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>
std::stack<int> stack;
if (isdigit(c)) {
stack.push(c - '0');
} else {
stack.pop();
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() {
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:**
- 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
```
```cpp
```
We call the `evaluatePostfix` function to evaluate the postfix expression and store 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:**
```
```
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.
Certainly! Let's discuss Polish notation (Prefix) and Reverse Polish notation (Postfix) expressions along
with their evaluation in C++, and provide examples for each.
- Polish notation eliminates the need for parentheses and makes expressions unambiguous.
**Example:**
**Compilation in C++:**
To evaluate a Polish expression, we can use a stack-based algorithm to process operators and
operands sequentially.
- Operators are written after their operands, making the expression unambiguous and eliminating
the need for parentheses.
**Example:**
**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.
```cpp
#include <iostream>
#include <stack>
#include <sstream>
#include <vector>
#include <string>
std::stack<int> stack;
std::stringstream ss(*it);
if (isdigit((*it)[0])) {
int operand;
ss >> operand;
stack.push(operand);
} else {
stack.pop();
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() {
return 0;
```
**Explanation:**
- The provided C++ code demonstrates how to evaluate a Reverse Polish expression using a stack-
based algorithm.
- The `main` function initializes an example Reverse Polish expression and evaluates it using the
`evaluatePolishExpression` function.
**Output:**
```
```
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>
int factorial(int n) {
if (n == 0) {
return 1;
int main() {
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:**
```
```
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:
2. Each move consists of taking the top disk from one stack and placing it onto another stack.
```cpp
#include <iostream>
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;
int main() {
std::cout << "Steps to solve Tower of Hanoi with " << numDisks << " disks:" << std::endl;
return 0;
```
**Explanation:**
- 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:**
```
```
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.
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:**
- 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:**
- **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.
**Circular Queue:**
- In a circular queue, after reaching the end of the array, the rear pointer wraps around to the
beginning of the array.
**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.
- Deques support insertion and deletion from both ends, making them versatile data structures.
**Applications of Queue:**
- **Breadth-First Search (BFS):** Queues are used to implement BFS algorithm for traversing graphs.
- **Simulations:** Queues are used to model various real-world scenarios such as traffic flow,
customer service, etc.
**Example Code:**
```cpp
#include <iostream>
#define MAX_SIZE 5
class Queue {
private:
int arr[MAX_SIZE];
public:
bool isEmpty() {
bool isFull() {
if (isFull()) {
return;
if (isEmpty()) {
front = rear = 0;
} else {
arr[rear] = value;
}
int dequeue() {
if (isEmpty()) {
return -1;
if (front == rear) {
} else {
return value;
int frontElement() {
if (isEmpty()) {
return -1;
return arr[front];
int rearElement() {
if (isEmpty()) {
return -1;
return arr[rear];
};
int main() {
Queue q;
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
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.
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>
#define MAX_SIZE 10
class PriorityQueue {
private:
int arr[MAX_SIZE]; // Array to store elements
public:
PriorityQueue() : rear(-1) {}
bool isEmpty() {
bool isFull() {
if (isFull()) {
return;
rear++;
arr[rear] = value;
priorities[rear] = priority;
} else {
break;
}
}
int dequeue() {
if (isEmpty()) {
return -1;
rear--;
return value;
int frontElement() {
if (isEmpty()) {
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 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 `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.
- In a singly linked list, each node contains a single link field pointing to the next node in the
sequence.
- 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.
- In a circular linked list, the last node of the list points back to the first node, forming a circular
structure.
- 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).
- Dequeue operation removes and returns the first element of the linked list.
- Implementing other data structures like stacks, queues, and hash tables.
**Example Code:**
Below is a simple implementation of a singly linked list-based stack and queue in C++:
```cpp
#include <iostream>
int data;
Node* next;
};
class Stack {
private:
Node* top;
public:
Stack() : top(nullptr) {}
bool isEmpty() {
newNode->next = top;
top = newNode;
int pop() {
if (isEmpty()) {
return -1;
delete temp;
return value;
};
class Queue {
private:
Node* front;
Node* rear;
public:
bool isEmpty() {
if (isEmpty()) {
} else {
rear->next = newNode;
rear = newNode;
int dequeue() {
if (isEmpty()) {
std::cout << "Queue is empty. Cannot dequeue." << std::endl;
return -1;
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);
Queue queue;
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
return 0;
```
**Explanation:**
- 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.