Unit III
Unit III
● Definition:
● Explanation:
○ Different types of data structures are suited for different kinds of applications.
● Example:
Data structures can be classified into different categories based on various factors:
A. Based on Simplicity
● Examples:
● Examples:
○ Arrays: Collection of elements of the same type stored in contiguous memory
locations.
B. Based on Structure
● Examples:
○ Linked List: A collection of nodes where each node contains data and a pointer
to the next node.
● Examples:
● Efficient Data Management: Helps in organizing data for efficient access and
modification.
4. Conclusion
● Choosing the right data structure is crucial for optimizing performance in software
development.
● Understanding the classification helps in selecting the appropriate structure for a given
problem.
Advantages and Disadvantages of Static Data Structure
● Data structure size is fixed.
● Not flexible.
● Stack is used in memory.
● Less efficient than a dynamic data structure.
● No memory reuse.
● Overflow is not possible.
● Memory allocation is done during compile time.
Algorithm Specification
1. Introduction
● Definition: An algorithm is a finite set of step by step instructions to solve a problem. In
normal language, algorithm is defined as a sequence of statements which are used
toperform a task. In computer science, an algorithm can be defined as follows: An
algorithm is a sequence of unambiguous instructions used for solving aproblem, which
can be implemented (as a program) on a computer. Properties Every algorithm must
satisfy the following properties: 1. Definiteness - Every step in an algorithm must be clear
and unambiguous 2. Finiteness – Every algorithm must produce result within a finite
number of steps. 3. Effectiveness - Every instruction must be executed in a finite amount
of time. 4. Input & Output - Every algorithm must take zero or more number of inputs and
must produce at least one output as result.
● Importance:
○ Helps in problem-solving
2. Recursive Algorithms
● Definition: An algorithm that calls itself to solve smaller subproblems.
● Basic Components:
●
● Advantages:
● Disadvantages:
3. Data Abstraction
● Definition: Hiding details of data structures and only exposing the necessary interface.
● Types:
○ Abstract Data Types (ADTs): Models like Stack, Queue, List, Graph, etc.
○ Encapsulation: Bundling data with methods to operate on it
○ Operations:
●
4. Performance Analysis
In computer science there are multiple algorithms to solve a problem. When we have
more than one algorithm to solve a problem, we need to select the best one.
Performance analysis helps us to select the best algorithm from multiple algorithms
to solve a problem.When there are multiple alternative algorithms to solve a problem,
we analyses them and pick the one which is best suitable for our requirements.
Generally, the performance of an algorithm depends on the following elements...
1. Whether that algorithm is providing the exact solution for the problem?
2. Whether it is easy to understand?
3. Whether it is easy to implement?
4. How much space (memory) it requires to solve the problem?
5. How much time it takes to solve the problem? Etc.,
When we want to analyze an algorithm, we consider only the space and time
required by that particular algorithm and we ignore all remaining
elements.Performance analysis of an algorithm is performed by using the following
measures:
1. Space Complexity
2. Time Complexity
Space complexity
Time complexity
following:
· Whether it is running on Single processor machine or Multi processor
machine.
· Whether it is a 32 bit machine or 64 bit machine
· Read and Write speed of the machine.
· The time it takes to perform Arithmetic operations, logical
operations, return value and assignment operations etc.,
NOTE: When we calculate time complexity of an algorithm, we consider only input data
and ignore the remaining things, as they are machine dependent.
Asymptotic Notation
values.
· Theta notation describes the average case of an algorithm time complexity.
· It is represented as Θ (T)
·
Example
Consider the following
piece of code
Algorithm Search (A,
n,x)
{ // where A is an array, n is the size of an array and x is the
item to be searched. for i := 1 to n do
{
if(x=A[i]) then
{
write (item found at location i) return;
}
}
write (item not found)
}
– The number K in A[K] is called subscript or an index and A[K] is called a subscripted
variable
Computer does not need to keep track of the address of every element of LA, but
need to track only the address of the first element of the array denoted by
Base(LA)
and called the base address of LA. Using this address, the computer calculates
the address of any element of LA by the following formula:
where w is the number of words per memory cell of the array LA [w is the size of the
data type] .
Example: Find the address for LA [6]. Each element of the array occupy 1 byte
In the row-major order layout (a opted by C for statically declared arrays), the elements of each row are
stored in consecutive position:
1 2 3
4 5 6
7 8 9
Lower bounds are the minimum values of i and j (usually 0 or 1 depending on the language or
system).
Row-Major Formula:
Apply values:
Answer: 1018
In Column-major order (traditionally used by Fortran), the elements of each column are consecutive in
memory:
4 5 6
7 8 9
Column-Major Formula:
Apply values:
Answer: 1010
1.Traversal
This operation is used to traverse or move through the elements of the array.
#include <iostream.h>
#include <conio.h>
void main() {
clrscr();
char fruits[5][20] = {
"Apple",
"Mango",
"Banana",
"Orange",
"Grapes"
};
getch();
}
Output
Apple
Mango
Banana
Orange
Grapes
2.Insertion
We can insert one or multiple elements in an array as per the requirement at the
required positions or indexes.
#include <iostream.h>
#include <conio.h>
void main() {
clrscr();
cout << "Enter position to insert (0 to " << n << "): ";
cin >> pos;
arr[pos] = value;
n++; // New size after insertion
getch();
}
3.Deletion
It is used to delete an element from a particular index in an array.
● Enter elements in an array
#include <iostream.h>
#include <conio.h>
void main() {
clrscr();
cout << "\nEnter position to delete (1 to " << n << "): ";
cin >> pos;
getch();
}
Enter number of elements in array: 5
Enter 5 elements:
Element 1: 10
Element 2: 20
Element 3: 30
Element 4: 40
Element 5: 50
4.Search
It is used to search an element using the given index or by the value. We can
search any element in an array and display both, its index and value.
#include <iostream.h>
#include <conio.h>
void main() {
clrscr();
// Linear search
for (i = 0; i < n; i++) {
if (arr[i] == key) {
found = 1;
break;
}
}
if (found)
cout << "\nElement " << key << " found at position " << i + 1 << ".";
else
cout << "\nElement " << key << " not found in the array.";
getch();
}
OUTPUT:-
Enter the number of elements (max 50): 5
Enter 5 elements:
Element 1: 12
Element 2: 45
Element 3: 23
Element 4: 89
Element 5: 67
6. Sparse Matrix
What is a matrix?
A matrix can be defined as a two-dimensional array having 'm' rows and 'n'
columns. A matrix with m rows and n columns is called m � n matrix. It is a set
of numbers that are arranged in the horizontal or vertical lines of entries.
For example -
Now, the question arises: we can also use the simple matrix to store the
elements, then why is the sparse matrix required?
Storage - We know that a sparse matrix contains lesser non-zero elements than
zero, so less memory can be used to store elements. It evaluates only the
non-zero elements.
0 where i > j.
Representation of Upper Triangular Sparse Matrix
A[5,5]
○ Array representation
○ Linked list representation
In 2D array representation of sparse matrix, there are three fields used that are
named as -
○ Row - It is the index of a row where a non-zero element is located in the matrix.
○ Column - It is the index of the column where a non-zero element is located in the
matrix.
○ Value - It is the value of the non-zero element that is located at the index (row,
column).
Example -
In the above figure, we can observe a 5x4 sparse matrix containing 7 non-zero
elements and 13 zero elements. The above matrix occupies 5x4 = 20 memory
space. Increasing the size of matrix will increase the wastage space.
The size of the table depends upon the total number of non-zero elements in the
given sparse matrix. Above table occupies 8x3 = 24 memory space which is
more than the space occupied by the sparse matrix. So, what's the benefit of
using the sparse matrix? Consider the case if the matrix is 8*8 and there are only
8 non-zero elements in the matrix, then the space occupied by the sparse matrix
would be 8*8 = 64, whereas the space occupied by the table represented using
triplets would be 8*3 = 24.
#include <iostream.h>
#include <conio.h>
void main() {
clrscr();
int i, j, size = 0;
getch();
}
Output:-
Row Col Value
0 2 6
0 4 9
1 2 4
1 3 6
3 1 1
3 2 2
Unlike the array representation, a node in the linked list representation consists of
four fields. The four fields of the linked list are given as follows -
○ Row - It represents the index of the row where the non-zero element is located.
○ Column - It represents the index of the column where the non-zero element is
located.
○ Value - It is the value of the non-zero element that is located at the index (row,
column).
○ Next node - It stores the address of the next node.
Example -
Let's understand the linked list representation of sparse matrix with the help of
the example given below -
In the above figure, we can observe a 4x4 sparse matrix containing 5 non-zero
elements and 11 zero elements. Above matrix occupies 4x4 = 16 memory space.
Increasing the size of matrix will increase the wastage space.
In the above figure, the sparse matrix is represented in the linked list form. In the
node, the first field represents the index of the row, the second field represents
the index of the column, the third field represents the value, and the fourth field
contains the address of the next node.
In the above figure, the first field of the first node of the linked list contains 0,
which means 0th row, the second field contains 2, which means 2nd column, and
the third field contains 1 that is the non-zero element. So, the first node
represents that element 1 is stored at the 0th row-2nd column in the given sparse
matrix. In a similar manner, all of the nodes represent the non-zero elements of
the sparse matrix.
void main() {
clrscr();
getch();
}
Output:-
Row Col Value
0 2 1
0 3 2
1 0 3
2 1 4
2 2 5
3 1 6
What is a Stack?
A stack is a linear data structure where elements are stored in the LIFO
(Last In First Out) principle where the last element inserted would be the
first element to be deleted. A stack is an Abstract Data Type (ADT), that is
popularly used in most programming languages. It is named stack because it
has the similar operations as the real-world stacks, for example − a pack of
cards or a pile of plates, etc.
Stack Representation
A stack allows all data operations at one end only. At any given time, we can
only access the top element of a stack.
The most fundamental operations in the stack ADT include: push(), pop(),
peek(), isFull(), isEmpty(). These are all built-in operations to carry out data
manipulation and to check the status of the stack.
Stack uses pointers that always point to the topmost element within the
stack, hence called as the top pointer.
Algorithm
Push Operation
Push Function -
Output:-
Algorithm
Pop Operation (POP())
1. Check if top == -1
2. If true, display 'Stack Underflow'
3. Else, store and display stack[top]
4. Decrease top by 1
5. End
Program code:-
Output:-
20 popped from stack.
10 popped from stack.
Algorithm
Output:-
Algorithm
isFull()
1. If top == MAX - 1
2. Return true (Stack is Full)
3. Else, return false
4. End
Program code:-
Output:-
If top = 4 and MAX = 5, isFull returns 1 (True).
Verifying whether the Stack is empty:
isEmpty()
The isEmpty() operation verifies whether the stack is empty. This operation is
used to check the status of the stack with the help of top pointer.
Algorithm
isEmpty()
1. If top == -1
2. Return true (Stack is Empty)
3. Else, return false
4. End
Program Code
int isEmpty(int top) {
return top == -1;
}
Example Output:
If top = -1, isEmpty returns 1 (True).
Stack empty: true
Traverse Operation:-
Displays all elements from top to bottom.
Example Output:
Stack elements are: 10
#include <iostream.h>
#include <conio.h>
#define MAX 5
// Function Prototypes
void push(int stack[], int &top, int value);
void pop(int stack[], int &top);
void peek(int stack[], int top);
int isFull(int top);
int isEmpty(int top);
void traverse(int stack[], int top);
void main() {
clrscr();
int stack[MAX];
int top = -1;
int choice, value;
do {
// Display Menu
cout << "\n--- Stack Operations Menu ---\n";
cout << "1. Push\n";
cout << "2. Pop\n";
cout << "3. Peek\n";
cout << "4. Traverse\n";
cout << "5. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
switch(choice) {
case 1:
cout << "Enter value to push: ";
cin >> value;
push(stack, top, value);
break;
case 2:
pop(stack, top);
break;
case 3:
peek(stack, top);
break;
case 4:
traverse(stack, top);
break;
case 5:
cout << "Exiting Program...";
break;
default:
cout << "Invalid Choice! Please try again.\n";
}
} while(choice != 5);
getch();
}
Output
--- Stack Operations Menu ---
1. Push
2. Pop
3. Peek
4. Traverse
5. Exit
Enter your choice: 1
Enter value to push: 10
10 pushed into stack.
In a linked list representation of a stack, each element is a node containing data and a pointer to
the next node, with the "top" pointer indicating the topmost element. Push and pop operations
occur at the top, making them O(1) operations.
Here's a more detailed explanation:
● Nodes: Each element in the stack is represented as a node in a linked list.
● Data and Pointer: Each node contains two parts:
○ Data: The actual value stored in the stack element.
○ Next Pointer: A pointer that points to the next node in the stack (or null for the last
node).
● Top Pointer: A pointer, often named "top", that always points to the topmost node in the
stack.
● Push Operation:
○ A new node is created with the data to be pushed.
○ The new node's "next" pointer is set to point to the current "top" node.
○ The "top" pointer is updated to point to the new node, making it the new top.
● Pop Operation:
○ The "top" node's data is retrieved.
○ The "top" pointer is updated to point to the next node in the stack.
○ The previous "top" node is removed from the stack (though the memory might be
reclaimed by the garbage collector).
● Advantages of Linked List Implementation:
○ Dynamic Size: Unlike array-based stacks, linked list stacks can grow or shrink
dynamically as needed, without a fixed size limitation.
○ Efficient Push and Pop: Push and pop operations, which are fundamental stack
operations, can be performed in constant time (O(1)) at the top of the linked list.
● Example:
Imagine a stack with elements 1, 2, and 3 (where 3 is at the top). In a linked list representation:
● Node 1: Data = 1, Next = Node 2
● Node 2: Data = 2, Next = Node 3
● Node 3: Data = 3, Next = null
● Top Pointer: Points to Node 3
Program
#include <iostream.h>
#include <conio.h>
void main() {
clrscr();
Node* top = NULL;
int choice, value;
do {
cout << "\n--- Stack (Linked List) Menu ---\n";
cout << "1. Push\n";
cout << "2. Pop\n";
cout << "3. Peek\n";
cout << "4. Traverse\n";
cout << "5. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
switch(choice) {
case 1:
cout << "Enter value to push: ";
cin >> value;
push(top, value);
break;
case 2:
pop(top);
break;
case 3:
peek(top);
break;
case 4:
traverse(top);
break;
case 5:
cout << "Exiting program...\n";
break;
default:
cout << "Invalid choice! Try again.\n";
}
} while(choice != 5);
getch();
}
Output:-
The following are the three different notations for writing the Arithmetic
expression.
Infix Expression
a + b * c
Infix expressions are easy to read, write and understand by humans, but not by
computer It’s costly, in terms of time and space, to process Infix expressions
abc*+
It’s the most used notation for evaluating arithmetic expressions
+a*bc
4 Additive +– Left to
Right
7 Equality == != Left to
Right
9 Bitwise ^ Left to
XOR Right
10 Bitwise OR | Left to
Right
13 Conditiona ?: Right to
l Left
15 Comma , Left to
Right
Conversion of Infix to Postfix can be done using stack. The stack is used to
reverse the order of operators. Stack stores the operator because it can not be
added to the postfix expression until both of its operands are added. The
precedence of the operator also matters while converting infix to postfix using
stack, which we will discuss in the algorithm. Note: Parentheses are used to
override the precedence of operators, and they can be nested parentheses
that need to be evaluated from inner to outer.
Algorithm for Conversion of Infix to Postfix using Stack in C++
Here are the steps of the algorithm to convert Infix to postfix using stack in C:
● Scan all the symbols one by one from left to right in the given Infix
Expression.
● If the reading symbol is an operand, then immediately append it to the
Postfix Expression.
● If the reading symbol is left parenthesis ‘( ‘, then Push it onto the Stack.
● If the reading symbol is right parenthesis ‘)’, then Pop all the contents of
the stack until the respective left parenthesis is popped and append
each popped symbol to Postfix Expression.
● If the reading symbol is an operator (+, –, *, /), then Push it onto the
Stack. However, first, pop the operators which are already on the stack
that have higher or equal precedence than the current operator and
append them to the postfix. If an open parenthesis is there on top of the
stack then push the operator into the stack.
● If the input is over, pop all the remaining symbols from the stack and
append them to the postfix.
Introduction
Stacks are used extensively in expression evaluation and syntax parsing. One of the key
applications of stacks is in the conversion of arithmetic expressions from one notation to
another, such as from infix to postfix or prefix. These conversions are important because postfix
and prefix notations are easier to evaluate programmatically.
Expression Notations
● Infix Expression: Operator is written between operands.
○ Example: A + B
○ Example: A B +
○ Example: + A B
3. Right Parenthesis ) pops from the stack to the postfix expression until ( is
encountered.
4. Operators:
○ Pop from the stack to postfix while the precedence of the top stack operator is
greater than or equal to the current operator.
(A + B) * (C - D) AB+CD-* *+AB-CD
(A + B) / (C - D) AB+CD-/ /+AB-CD
A + (B * C - D) / E ABC*D-E/+ +A/-*BCDE
(A + B * C) ^ D ABC*+D^ ^+A*BCD
A + ((B + C) * (D + E)) ABC+DE+*+ +A*+BC+DE
(A + B) * (C + D) AB+CD+* *+AB+CD
A * (B + C * D) ABCD*+* *A+B*CD
3. On operator, pop two elements, apply the operator, and push the result.
Postfix: 5 6 2 + *
● Push 5, 6, 2
● Encounter +: 6 + 2 = 8
● Push 8
● Encounter *: 5 * 8 = 40
● Final Result: 40
3. On operator, pop two operands, apply operator, and push result.
Prefix: * 5 + 6 2
● Read 2, 6, + → 6 + 2 = 8
● Push 8
● Read 5, * → 5 * 8 = 40
● Final Result: 40
🧮 Expression 2:
Infix:
A + B * (C ^ D - E) ^ (F + G * H) - I
✏️ Expected:
Postfix: ABCD^E- FGH*+^*+I-
Prefix: -+A*B^-CDE^+FGH I
🧮 Expression 3:
Infix:
(A + B * C) / ((D - E) + F)
✏️ Expected:
Postfix: ABC*+DE-F+/
Prefix: /+A*BC+ -DE F
🧮 Expression 4:
Infix:
A * (B + C * (D + E))
✏️ Expected:
Postfix: ABCDE+*+*
Prefix: *A+B*C+DE
🧮 Expression 5:
Infix:
((A + B) * (C - D)) / (E + F)
✏️ Expected:
Postfix: AB+CD-*EF+/
Prefix: / *+AB-CD +EF
🧮 Expression 6:
Infix:
(A + B * C) ^ (D - E + F)
✏️ Expected:
Postfix: ABC*+DE-F+^
Prefix: ^+A*BC+ -DE F
🧮 Expression 7:
Infix:
A + ((B + C) * (D + E))
✏️ Expected:
Postfix: ABC+DE+*+
Prefix: +A*+BC+DE
1. Introduction
In arithmetic expressions, the order of operators and operands matters. There are three
main types of notation:
○ Example: A + B
○ Example: + A B
● Postfix Notation (Reverse Polish Notation): Operators are written after operands.
○ Example: A B +
○ Parentheses ()
○ Exponentiation ^
○ Multiplication/Division *, /
○ Addition/Subtraction +, -
● Associativity:
○ Left to Right: +, -, *, /
○ Right to Left: ^
○ Pop from stack to output until the top has less precedence.
7. After the expression, pop all operators from the stack to the output.
● Push 5
● Push 6
● Push 2
● 2 + 6 = 8
● 5 * 8 = 40 Result: 40
● Read 2 → push
● Read 6 → push
● Read 5 → push
● Read + → 5 + 6 = 11
8. Summary Table
Expression Example Evaluation Order
Type
9. Practice Problems
Convert to Postfix:
1. A + B * C
2. (A + B) * (C - D)
3. A + B + C + D
Convert to Prefix:
1. A + B * C
2. A * (B + C)
3. (A - B) / (C + D)
1. Postfix: A B + C *
2. Prefix: + A * B C
These rules and examples help in mastering expression conversions and evaluations
which are crucial in compiler design, data structure processing, and algorithm
development.
Program:
#include <iostream.h>
#include <conio.h>
int factorial(int n) {
if(n == 1)
return 1;
else
return n * factorial(n - 1);
}
void main() {
clrscr();
int num = 4;
int result = factorial(num);
cout << "Factorial of " << num << " is: " << result;
getch();
}
Output:
Factorial of 4 is: 24
Return Sequence:
factorial(1) = 1
factorial(2) = 2 * 1 = 2
factorial(3) = 3 * 2 = 6
factorial(4) = 4 * 6 = 24
Program:
#include <iostream.h>
#include <conio.h>
int fibonacci(int n) {
if(n == 0)
return 0;
else if(n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
void main() {
clrscr();
int i, n = 6;
cout << "Fibonacci series up to " << n << " terms:\n";
for(i = 0; i < n; i++)
cout << fibonacci(i) << " ";
getch();
}
Output:
Fibonacci series up to 6 terms:
011235
Key Points:
- Recursion uses the stack to track function calls and returns.
- Factorial recursion is linear (one call per depth).
- Fibonacci recursion is tree-like (multiple branches per call), causing many repeated calls.
- Recursive Fibonacci is elegant but inefficient for large inputs (can be improved using iteration or
memoization).
Queue
What is a Queue?
A queue is a linear data structure where elements are stored in the FIFO (First
In First Out) principle where the first element inserted would be the first
element to be accessed. A queue is an Abstract Data Type (ADT) similar to
stack, the thing that makes queue different from stack is that a queue is open
at both its ends. The data is inserted into the queue through one end and
deleted from it using the other end. Queue is very frequently used in most
programming languages.
Representation of Queues
Similar to the stack ADT, a queue ADT can also be implemented using arrays,
linked lists, or pointers. As a small example in this tutorial, we implement
queues using a one-dimensional array.
1. INSERT (Enqueue)
· 👉 THEORY:
Insert operation adds an element to the rear end of the queue. If the rear reaches
the maximum size, the queue is said to be full (overflow).
· 📌 ALGORITHM:
1. Step 1: Check if rear == MAX - 1 → Overflow
· 🔎 EXAMPLE OUTPUT:
Enter value to insert: 10
10 inserted into queue.
2. DELETE (Dequeue)
· 👉 THEORY:
Delete operation removes an element from the front end of the queue. If front >
rear or front == -1, the queue is empty (underflow).
· 📌 ALGORITHM:
5. Step 1: Check if front == -1 or front > rear → Underflow
· 🔎 EXAMPLE OUTPUT:
10 deleted from queue.
3. PEEK
· 👉 THEORY:
Peek operation displays the front element of the queue without removing it.
· 📌 ALGORITHM:
8. Step 1: Check if front == -1 or front > rear → Queue is empty
· 🔎 EXAMPLE OUTPUT:
Front element is: 20
4. TRAVERSE
· 👉 THEORY:
Traverse operation displays all the elements in the queue from front to rear.
· 📌 ALGORITHM:
10. Step 1: Check if front == -1 or front > rear → Queue is empty
· 🔎 EXAMPLE OUTPUT:
Queue elements are: 20 30
1. INSERT (Enqueue)
· 👉 THEORY:
Adds a new element to the rear (end) of the linked list queue.
· 📌 ALGORITHM:
1. Step 1: Create a new node.
4. Step 4: Else, rear->next = new node and update rear to new node
· 💻 FUNCTION CODE IN C++:
void insert(Node* &front, Node* &rear, int value) {
Node *temp = new Node;
if (temp == NULL) {
cout << "Queue Overflow!\n";
return;
}
temp->data = value;
temp->next = NULL;
if (front == NULL) {
front = rear = temp;
} else {
rear->next = temp;
rear = temp;
}
cout << value << " inserted into queue.\n";
}
· 🔎 EXAMPLE OUTPUT:
Enter value to insert: 10
10 inserted into queue.
2. DELETE (Dequeue)
· 👉 THEORY:
Removes an element from the front of the queue.
· 📌 ALGORITHM:
5. Step 1: Check if front is NULL → Underflow
· 🔎 EXAMPLE OUTPUT:
10 deleted from queue.
3. PEEK
· 👉 THEORY:
Displays the front element of the queue.
· 📌 ALGORITHM:
9. Step 1: Check if front is NULL → Queue is empty
4. TRAVERSE
· 👉 THEORY:
Prints all the elements in the queue from front to rear.
· 📌 ALGORITHM:
11. Step 1: Check if front is NULL → Queue is empty
12. Step 2: Loop through the linked list and print each node’s data
· 🔎 EXAMPLE OUTPUT:
Queue elements are: 20 30
Full Queue Program Using Linked List in
Turbo C++
#include <iostream.h>
#include <conio.h>
struct Node {
int data;
Node *next;
};
void insert(Node* &front, Node* &rear, int value);
void deleteItem(Node* &front, Node* &rear);
void peek(Node* front);
void traverse(Node* front);
void main() {
clrscr();
Node *front = NULL, *rear = NULL;
int choice, value;
do {
cout << "\n--- Queue Menu ---\n";
cout << "1. Insert\n";
cout << "2. Delete\n";
cout << "3. Peek\n";
cout << "4. Traverse\n";
cout << "5. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
switch(choice) {
case 1:
cout << "Enter value to insert: ";
cin >> value;
insert(front, rear, value);
break;
case 2:
deleteItem(front, rear);
break;
case 3:
peek(front);
break;
case 4:
traverse(front);
break;
case 5:
cout << "Exiting program...\n";
break;
default:
cout << "Invalid choice!\n";
}
} while(choice != 5);
getch();
}
// Function Definitions
void insert(Node* &front, Node* &rear, int value) {
Node *temp = new Node;
if (temp == NULL) {
cout << "Queue Overflow!\n";
return;
}
temp->data = value;
temp->next = NULL;
if (front == NULL) {
front = rear = temp;
} else {
rear->next = temp;
rear = temp;
}
cout << value << " inserted into queue.\n";
}
void deleteItem(Node* &front, Node* &rear) {
if (front == NULL) {
cout << "Queue Underflow!\n";
return;
}
Node *temp = front;
cout << front->data << " deleted from queue.\n";
front = front->next;
delete temp;
if (front == NULL)
rear = NULL;
}
void peek(Node* front) {
if (front == NULL) {
cout << "Queue is Empty!\n";
} else {
cout << "Front element is: " << front->data << "\n";
}
}
void traverse(Node* front) {
if (front == NULL) {
cout << "Queue is Empty!\n";
} else {
cout << "Queue elements are: ";
while (front != NULL) {
cout << front->data << " ";
front = front->next;
}
cout << "\n";
}
}
Types of deque
There are two types of deque -
In input restricted queue, insertion operation can be performed at only one end, while deletion
can be performed from both ends.
In output restricted queue, deletion operation can be performed at only one end, while insertion
can be performed from both ends.
○ Insertion at front
○ Insertion at rear
○ Deletion at front
○ Deletion at rear
We can also perform peek operations in the deque along with the operations
listed above. Through peek operation, we can get the deque's front and rear
elements of the deque. So, in addition to the above operations, following
operations are also supported in deque -
In this operation, the element is inserted from the front end of the queue. Before implementing
the operation, we first have to check whether the queue is full or not. If the queue is not full, then
the element can be inserted from the front end by using the below conditions -
○ If the queue is empty, both rear and front are initialized with 0. Now, both will point to the
first element.
○ Otherwise, check the position of the front if the front is less than 1 (front < 1), then
reinitialize it by front = n - 1, i.e., the last index of the array.
Algorithm:
1. Start.
2. Check if the queue is full: (front == 0 && rear == size - 1) ||
(front == rear + 1) → Overflow.
7. Stop.
In this operation, the element is inserted from the rear end of the queue. Before implementing
the operation, we first have to check again whether the queue is full or not. If the queue is not
full, then the element can be inserted from the rear end by using the below conditions -
○ If the queue is empty, both rear and front are initialized with 0. Now, both will point to the
first element.
○ Otherwise, increment the rear by 1. If the rear is at last index (or size - 1), then instead of
increasing it by 1, we have to make it equal to 0.
Algorithm:
1. Start.
7. Stop.
In this operation, the element is deleted from the front end of the queue. Before implementing
the operation, we first have to check whether the queue is empty or not.
If the queue is empty, i.e., front = -1, it is the underflow condition, and we cannot perform the
deletion. If the queue is not full, then the element can be inserted from the front end by using the
below conditions -
If the deque has only one element, set rear = -1 and front = -1.
Else if front is at end (that means front = size - 1), set front = 0.
Else increment the front by 1, (i.e., front = front + 1).
Algorithm:
1. Start.
7. Stop.
In this operation, the element is deleted from the rear end of the queue. Before
implementing the operation, we first have to check whether the queue is empty or
not.
If the queue is empty, i.e., front = -1, it is the underflow condition, and we cannot
perform the deletion.
If the deque has only one element, set rear = -1 and front = -1.
7. Stop.
Check empty
This operation is performed to check whether the deque is empty or not. If front =
-1, it means that the deque is empty.
Algorithm:
1. Start.
4. Stop.
Check full
This operation is performed to check whether the deque is full or not. If front =
rear + 1, or front = 0 and rear = n - 1 it means that the deque is full.
The time complexity of all of the above operations of the deque is O(1), i.e.,
constant.
Algorithm:
1. Start.
4. Stop.
Applications of deque
○ Deque can be used as both stack and queue, as it supports both operations.
○ Deque can be used as a palindrome checker means that if we read the string
from both ends, the string would be the same.
Circular Queue
There was one limitation in the array implementation of Queue. If the rear
reaches to the end position of the Queue then there might be possibility that
some vacant spaces are left in the beginning which cannot be utilized. So, to
overcome such limitations, the concept of the circular queue was introduced.
● Although there are empty spaces in the array (before front), new elements can't be
inserted.
● But shifting elements takes extra time and makes insertion inefficient.
🔹 Efficient Solution
● Use a Circular Queue.
● In a circular queue, the rear can wrap around to the front when space is available.
Enqueue operation
The steps of enqueue operation are given below:
○ If rear != max - 1, then rear will be incremented to mod(maxsize) and the new
value will be inserted at the rear end of the queue.
○ If front != 0 and rear = max - 1, it means that queue is not full, then set the value
of rear to 0 and insert the new element there.
○ When front ==0 && rear = max-1, which means that front is at the first position of
the Queue and rear is at the last position of the Queue.
○ front== rear + 1;
Step 1:
If (FRONT == 0 AND REAR == MAX - 1)
OR (FRONT == REAR + 1)
→ Print "OVERFLOW"
→ Go to Step 6
[End of IF]
Step 2:
If FRONT == -1 (Queue is empty)
→ Set FRONT = 0, REAR = 0
Step 3:
Else if REAR == MAX - 1 AND FRONT != 0
→ Set REAR = 0
Step 4:
Else
→ Set REAR = REAR + 1
Step 5:
Set QUEUE[REAR] = VAL (Insert the value)
Step 6:
EXIT
Functiom code:-
void insert(int QUEUE[], int &FRONT, int &REAR, int MAX, int VAL)
{
// Step 1: Check for Overflow
if ((FRONT == 0 && REAR == MAX - 1) || (FRONT == REAR + 1))
{
cout << "OVERFLOW";
return; // Step 6: EXIT
}
Output:-
● QUEUE[0] = 10
➡️ QUEUE: [10, _, _, _, _]
Operation 2: insert(QUEUE, FRONT, REAR, MAX, 20);
● REAR = 1
● QUEUE[1] = 20
➡️ QUEUE: [10, 20, _, _, _]
Operation 3: insert(QUEUE, FRONT, REAR, MAX, 30);
● REAR = 2
● QUEUE[2] = 30
● QUEUE[3] = 40
● QUEUE[4] = 50
● Output: OVERFLOW
➡️ No change in QUEUE
Dequeue Operation
The steps of dequeue operation are given below:
○ First, we check whether the Queue is empty or not. If the queue is empty, we
cannot perform the dequeue operation.
○ When the element is deleted, the value of front gets decremented by 1.
○ If there is only one element left which is to be deleted, then the front and rear are
reset to -1.
Step 4: EXIT
FUNCTION CODE:-
void deleteElement() {
int val;
// Step 4: EXIT
}
Output:-
Deleted element: 10
Deleted element: 20
Deleted element: 30
UNDERFLOW
Sample Output
---- Circular Queue Menu ----
1. Insert
2. Delete
3. Display
4. Exit
Enter your choice: 1
Enter element to insert: 10
Inserted: 10
Enter your choice: 1
Enter element to insert: 20
Inserted: 20
Enter your choice: 3
Queue Elements: 10 20
Enter your choice: 2
Deleted: 10
Enter your choice: 3
Queue Elements: 20
Enter your choice: 4
Exiting...
🔶 What is a Priority Queue?
● A priority queue is a type of queue where each element is assigned a priority.
● Elements are arranged based on their priority values, not just the order of insertion.
● Binary Heap is the most common data structure used to implement priority queues.
🔶 Key Characteristics
● Each element has an associated priority.
○ Cache-friendly performance.
● Example: The element with the highest value is placed at the top (root in heap) and
dequeued first.
2. Deletion:
3. Peek:
struct item {
int item;
int priority;
}
● enqueue(): This function is used to insert new data into the queue.
peek(
Arrays enqueue() dequeue()
)
2. Start from the end of the array and shift elements with lower priority one position to the
right.
3. Find the correct position where the new item should be inserted.
Function:
struct item {
int data;
int priority;
};
cout << "Inserted: (" << value << ", " << p << ")" << endl;
}
Example Output:
📌 Sample Output
If we insert like this:
Inserted: (20, 4)
Inserted: (10, 2)
Function:
struct Item {
int data;
int priority;
};
(*n)--;
}
Example Output
Output:
makefile
CopyEdit
Deleted: (20, 4)
Queue: (10, 2)
○ If the queue is empty (n == 0), display "Queue is empty!" and exit the function.
● (30, 3)
● (10, 1)
Function Call:
peek(pq, 3);
Output:
Front Element: (50, 5)
Explanation:
● The peek function will display the element at the front of the queue (i.e., the first
element), which is (50, 5) in this case.
● It prints the data and priority of the front element without removing it from the queue.
○ Traverse the queue from index 0 to n-1 and print each element along with its
priority.
Function:
Let's assume the priority queue (pq) has the following elements:
Function Call:
traverse(pq, 3); // Here, '3' represents the number of elements in the queue
Output:-
Queue elements:
(50, 5)
(30, 3)
(10, 1)
Explanation:
● The traverse function prints each element in the queue along with its priority.
● The elements are displayed in the order they appear in the array, starting from
index 0 to n-1 (where n is the number of elements).
struct item {
int data;
int priority;
};
void main() {
struct item pq[SIZE];
int n = 0, choice, value, priority;
clrscr();
do {
printf("\n--- Priority Queue Menu ---\n");
printf("1. Insert\n2. Delete\n3. Peek\n4. Traverse\n5. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Enter value and priority: ");
scanf("%d%d", &value, &priority);
enqueue(pq, &n, value, priority);
break;
case 2:
dequeue(pq, &n);
break;
case 3:
peek(pq, n);
break;
case 4:
traverse(pq, n);
break;
case 5:
printf("Exiting...\n");
break;
default:
printf("Invalid choice!\n");
}
} while (choice != 5);
getch();
}
Sample Output
--- Priority Queue Menu ---
1. Insert
2. Delete
3. Peek
4. Traverse
5. Exit
Enter your choice: 1
Enter value and priority: 40 3
LINKED LIST
A Linked List is a linear data structure that is a collection of objects, called nodes. Each node in
a linked list consists of two parts, the first part contains the Data and the second part contains
the Address of the next node in the Linked List. A Linked List is a dynamic data structure, i.e.,
memory is allocated at run time, and memory size can be changed at run time according to our
requirements.
Types of Linkedlist
A singly linked list is a fundamental data structure, it consists of nodes where each node
contains a data field and a reference to the next node in the linked list. The next of the last
node is null, indicating the end of the list. Linked Lists support efficient insertion and deletion
operations.
Singly linked list can be defined as the collection of ordered set of elements. The number of
elements may vary according to need of the program. A node in the singly linked list consist of
two parts: data part and link part. Data part of the node stores actual information that is to be
represented by the node while the link part of the node stores the address of its immediate
successor.
One way chain or singly linked list can be traversed only in one direction. In other words, we
can say that each node contains only next pointer, therefore we can not traverse the list in the
reverse direction.
struct Node {
int data;
Node* next;
};
• Insertion at beginning
• Insertion at end
2. Deletion
3. Traversing list
4. Searching
5. concatenating
6. Sorting List
1. Insertion
Linked List Operations in C++ (Turbo C++)
Algorithm:
· 1. Start from the head.
· 2. Print each node's data.
· 3. Move to the next node until NULL is reached.
·
· Code:
· void display() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
Node* temp = head;
cout << "Linked List: ";
while (temp != NULL) {
cout << temp->data << " -> ";
temp = temp->next;
}
cout << "NULL\n";
}
·
· Example Output:
Linked List: 10 -> 20 -> 30 -> NULL
Insertion at Beginning
It involves inserting any element at the front of the list. We just need to a few link adjustments
to make the new node as the head of the list.
· Algorithm:
· 1. Create a new node.
· 2. Point its next to head.
· 3. Update head to the new node.
·
· Code:
· void insertFirst(int value) {
Node* newNode = createNode(value);
newNode->next = head;
head = newNode;
cout << "Inserted at beginning.\n";
}
·
· Example Output:
Enter value: 10
Inserted at beginning.
Linked List: 10 -> NULL
Insertion at End
It involves insertion at the last of the linked list. The new node can be inserted
as the only node in the list or it can be inserted as the last one. Different logics
are implemented in each scenario.
· Algorithm:
· 1. Create a new node.
· 2. If head is NULL, head = new node.
· 3. Else, traverse to last node and set its next to new node.
·
· Code:
· void insertLast(int value) {
Node* newNode = createNode(value);
if (head == NULL) {
head = newNode;
} else {
Node* temp = head;
while (temp->next != NULL)
temp = temp->next;
temp->next = newNode;
}
cout << "Inserted at last.\n";
}
·
· Example Output:
Enter value: 20
Inserted at last.
Linked List: 10 -> 20 -> NULL
· Algorithm:
· Code:
· void deleteFirst() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
Node* temp = head;
head = head->next;
delete temp;
cout << "Deleted from beginning.\n";
}
Example Output:
Deleted from beginning.
Linked List: 15 -> 20 -> NULL
· Algorithm:
· Code:
· void deleteLast() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
if (head->next == NULL) {
delete head;
head = NULL;
} else {
Node* temp = head;
while (temp->next->next != NULL)
temp = temp->next;
delete temp->next;
temp->next = NULL;
}
cout << "Deleted from last.\n";
}
· Example Output:
Deleted from last.
Linked List: 15 -> NULL
· Algorithm:
· Code:
· Example Output:
Enter position: 2
Deleted from position 2.
Linked List: 10 -> 20 -> NULL
Algorithm
1. Start from the head node.
4. If the end of the list is reached without a match, return not found.
Example Output
Case 1: Element is present
3. Set the next of the last node to the head of the second list.
void concatenate(Node* head1, Node* head2) {
if (head1 == NULL) {
head = head2;
return;
}
Node* temp = head1;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = head2;
head = head1;
cout << "Lists concatenated successfully.\n";
}
Example Output
List 1: 10 -> 20 -> 30
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
struct Node {
int data;
Node* next;
};
// Insert at beginning
void insertFirst(int value) {
Node* newNode = createNode(value);
newNode->next = head;
head = newNode;
cout << "Inserted at beginning.\n";
}
// Insert at last
void insertLast(int value) {
Node* newNode = createNode(value);
if (head == NULL) {
head = newNode;
} else {
Node* temp = head;
while (temp->next != NULL)
temp = temp->next;
temp->next = newNode;
}
cout << "Inserted at last.\n";
}
newNode->next = temp->next;
temp->next = newNode;
cout << "Inserted at position " << pos << ".\n";
}
if (temp->next == NULL) {
cout << "Invalid position!\n";
return;
}
Node* del = temp->next;
temp->next = del->next;
delete del;
cout << "Deleted from position " << pos << ".\n";
}
// Display list
void display() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
Node* temp = head;
cout << "Linked List: ";
while (temp != NULL) {
cout << temp->data << " -> ";
temp = temp->next;
}
cout << "NULL\n";
}
void main() {
clrscr();
int choice, value, pos;
do {
cout << "\n--- Singly Linked List Menu ---\n";
cout << "1. Insert at Beginning\n";
cout << "2. Insert at Last\n";
cout << "3. Insert at Position\n";
cout << "4. Delete from Beginning\n";
cout << "5. Delete from Last\n";
cout << "6. Delete from Position\n";
cout << "7. Display List\n";
cout << "8. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
switch (choice) {
case 1:
cout << "Enter value: ";
cin >> value;
insertFirst(value);
break;
case 2:
cout << "Enter value: ";
cin >> value;
insertLast(value);
break;
case 3:
cout << "Enter value: ";
cin >> value;
cout << "Enter position: ";
cin >> pos;
insertAtPos(value, pos);
break;
case 4:
deleteFirst();
break;
case 5:
deleteLast();
break;
case 6:
cout << "Enter position: ";
cin >> pos;
deleteAtPos(pos);
break;
case 7:
display();
break;
case 8:
cout << "Exiting...\n";
break;
default:
cout << "Invalid choice!\n";
}
} while (choice != 8);
getch();
}
Output:-
--- Singly Linked List Menu ---
1. Insert at Beginning
2. Insert at Last
3. Insert at Position
4. Delete from Beginning
5. Delete from Last
6. Delete from Position
7. Display List
8. Exit
Enter your choice: 1
Enter value: 10
Inserted at beginning.
✓ Doubly Linkedlist :
Doubly linked list is a complex type of linked list in which a node contains a pointer to the
previous as well as the next node in the sequence. Therefore, in a doubly linked list, a node
consists of three parts: node data, pointer to the next node in sequence (next pointer) , pointer
to the previous node (previous pointer).
Each node of a doubly linked list (DLL) consists of three fields:
● Item or Data: It is the value stored in the node.
Definition: A Doubly Linked List is a linear data structure where each node contains three fields:
one to store data, one pointing to the previous node, and one pointing to the next node in the
sequence.
Insertion Operations
1. Insertion at the Beginning (Head)
Algorithm:
1. Create a new node.
Function Code:
void insertAtBeginning(int value) {
Node *newNode = new Node;
newNode->data = value;
newNode->prev = NULL;
newNode->next = head;
if (head != NULL)
head->prev = newNode;
head = newNode;
cout << "Inserted at beginning.\n";
}
Example Output:
Enter value: 10
Inserted at beginning.
Doubly Linked List: 10 <-> NULL
Function Code:
void insertAtEnd(int value) {
Node *newNode = new Node;
newNode->data = value;
newNode->next = NULL;
if (head == NULL) {
newNode->prev = NULL;
head = newNode;
} else {
Node *temp = head;
while (temp->next != NULL)
temp = temp->next;
temp->next = newNode;
newNode->prev = temp;
}
cout << "Inserted at end.\n";
}
Example Output:
Enter value: 20
Inserted at end.
Doubly Linked List: 10 <-> 20 <-> NULL
Function Code:
void insertAtPosition(int value, int pos) {
if (pos <= 1) {
insertAtBeginning(value);
return;
}
if (temp == NULL) {
cout << "Position out of range.\n";
return;
}
newNode->next = temp->next;
newNode->prev = temp;
if (temp->next != NULL)
temp->next->prev = newNode;
temp->next = newNode;
cout << "Inserted at position " << pos << ".\n";
}
Example Output:
Enter value and position: 15 2
Inserted at position 2.
Doubly Linked List: 10 <-> 15 <-> 20 <-> NULL
Deletion Operations
1. Deletion from the Beginning
Algorithm:
1. If head is NULL, list is empty.
Function Code:
void deleteFromBeginning() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
if (head != NULL)
head->prev = NULL;
delete temp;
cout << "Deleted from beginning.\n";
}
Example Output:
Deleted from beginning.
Doubly Linked List: 15 <-> 20 <-> NULL
Function Code:
void deleteFromEnd() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
temp->prev->next = NULL;
delete temp;
}
cout << "Deleted from end.\n";
}
Example Output:
Deleted from end.
Doubly Linked List: 15 <-> NULL
Function Code:
void deleteFromPosition(int pos) {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
if (pos == 1) {
deleteFromBeginning();
return;
}
if (temp == NULL) {
cout << "Position out of range.\n";
return;
}
if (temp->next != NULL)
temp->next->prev = temp->prev;
if (temp->prev != NULL)
temp->prev->next = temp->next;
delete temp;
cout << "Deleted from position " << pos << ".\n";
}
Example Output:
Enter position to delete: 1
Deleted from position 1.
Doubly Linked List: NULL
Traversal
Algorithm:
1. Start from head.
Function Code:
void displayList() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
Example Output:
Doubly Linked List: 10 <-> 20 <-> 30 <-> NULL
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
struct Node {
int data;
Node *prev;
Node *next;
};
if (head != NULL)
head->prev = newNode;
head = newNode;
cout << "Inserted at beginning.\n";
}
temp->next = newNode;
newNode->prev = temp;
}
cout << "Inserted at end.\n";
}
if (temp == NULL) {
cout << "Position out of range.\n";
return;
}
newNode->next = temp->next;
newNode->prev = temp;
if (temp->next != NULL)
temp->next->prev = newNode;
temp->next = newNode;
cout << "Inserted at position " << pos << ".\n";
}
void deleteFromBeginning() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
Node *temp = head;
head = head->next;
if (head != NULL)
head->prev = NULL;
delete temp;
cout << "Deleted from beginning.\n";
}
void deleteFromEnd() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
temp->prev->next = NULL;
delete temp;
}
cout << "Deleted from end.\n";
}
if (pos == 1) {
deleteFromBeginning();
return;
}
if (temp == NULL) {
cout << "Position out of range.\n";
return;
}
if (temp->next != NULL)
temp->next->prev = temp->prev;
if (temp->prev != NULL)
temp->prev->next = temp->next;
delete temp;
cout << "Deleted from position " << pos << ".\n";
}
void displayList() {
if (head == NULL) {
cout << "List is empty.\n";
return;
}
void main() {
clrscr();
int choice, value, pos;
do {
cout << "\n--- Doubly Linked List Menu ---\n";
cout << "1. Insert at Beginning\n";
cout << "2. Insert at Position\n";
cout << "3. Insert at End\n";
cout << "4. Delete from Beginning\n";
cout << "5. Delete from Position\n";
cout << "6. Delete from End\n";
cout << "7. Display List\n";
cout << "8. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
switch (choice) {
case 1:
cout << "Enter value: ";
cin >> value;
insertAtBeginning(value);
break;
case 2:
cout << "Enter value and position: ";
cin >> value >> pos;
insertAtPosition(value, pos);
break;
case 3:
cout << "Enter value: ";
cin >> value;
insertAtEnd(value);
break;
case 4:
deleteFromBeginning();
break;
case 5:
cout << "Enter position to delete: ";
cin >> pos;
deleteFromPosition(pos);
break;
case 6:
deleteFromEnd();
break;
case 7:
displayList();
break;
case 8:
cout << "Exiting program.\n";
break;
default:
cout << "Invalid choice!\n";
}
} while (choice != 8);
getch();
}
Output:-
Or
A Circular Singly Linked List is a linear data structure where the last node points to the first
node, forming a circle. Unlike a singly linked list which ends with NULL, the circular list’s last
node links back to the head, allowing continuous traversal.
Insertion Operations
1. Insertion at Beginning
· Algorithm:
Function Code:
void insertAtBeginning(int value) {
Node *newNode = new Node;
newNode->data = value;
if (head == NULL) {
newNode->next = newNode;
head = newNode;
} else {
Node *temp = head;
while (temp->next != head)
temp = temp->next;
newNode->next = head;
temp->next = newNode;
head = newNode;
}
}
· Example Output:
Inserted 10 at beginning. List: 10 -> (head)
2. Insertion at End
· Algorithm:
Function Code:
void insertAtEnd(int value) {
Node *newNode = new Node;
newNode->data = value;
if (head == NULL) {
newNode->next = newNode;
head = newNode;
} else {
Node *temp = head;
while (temp->next != head)
temp = temp->next;
temp->next = newNode;
newNode->next = head;
}
}
· Example Output:
Inserted 20 at end. List: 10 -> 20 -> (head)
Deletion Operations
1. Deletion from Beginning
· Algorithm:
Function Code:
void deleteFromBeginning() {
if (head == NULL)
return;
if (head->next == head) {
delete head;
head = NULL;
} else {
Node *temp = head;
Node *last = head;
while (last->next != head)
last = last->next;
last->next = head->next;
head = head->next;
delete temp;
}
}
· Example Output:
Deleted from beginning. List: 20 -> (head)
Function Code:
void deleteFromEnd() {
if (head == NULL)
return;
if (head->next == head) {
delete head;
head = NULL;
} else {
Node *temp = head;
while (temp->next->next != head)
temp = temp->next;
Node *last = temp->next;
temp->next = head;
delete last;
}
}
· Example Output:
Deleted from end. List: 10 -> (head)
Traversal
· Algorithm:
Function Code:
void displayList() {
if (head == NULL) {
cout << "List is empty." << endl;
return;
}
Node *temp = head;
do {
cout << temp->data << " -> ";
temp = temp->next;
} while (temp != head);
cout << "(head)" << endl;
}
Example Output:
List: 10 -> 20 -> (head)
Definition
A Circular Doubly Linked List is a type of doubly linked list in which the last node points to the
first node and the first node points to the last node. Each node has three parts: data, a pointer to
the next node, and a pointer to the previous node. It allows traversal in both directions and
forms a circular loop.
Insertion Operations
1. Insertion at Beginning
Algorithm:
1. Create a new node.
2. If list is empty, point new node to itself in both directions and make it head.
3. Otherwise, adjust new node links and update head and tail links accordingly.
Function Code:
void insertAtBeginning(int value) {
Node* newNode = new Node;
newNode->data = value;
if (head == NULL) {
newNode->next = newNode;
newNode->prev = newNode;
head = newNode;
} else {
Node* tail = head->prev;
newNode->next = head;
newNode->prev = tail;
head->prev = newNode;
tail->next = newNode;
head = newNode;
}
}
Example Output:
Inserted 10 at beginning. List: 10 <-> (head)
2. Insertion at End
Algorithm:
1. Create a new node.
2. If list is empty, point new node to itself in both directions and make it head.
3. Otherwise, adjust links of the last node, new node, and head.
Function Code:
void insertAtEnd(int value) {
Node* newNode = new Node;
newNode->data = value;
if (head == NULL) {
newNode->next = newNode;
newNode->prev = newNode;
head = newNode;
} else {
Node* tail = head->prev;
newNode->next = head;
newNode->prev = tail;
tail->next = newNode;
head->prev = newNode;
}
}
Example Output:
Inserted 20 at end. List: 10 <-> 20 <-> (head)
Deletion Operations
Example Output:
Deleted from beginning. List: 20 <-> (head)
Example Output:
Deleted from end. List: 10 <-> (head)
Traversal
Algorithm:
1. Start from head.
2. Traverse using next pointers and print data until you reach head again.
Function Code:
void displayList() {
if (head == NULL) {
cout << "List is empty." << endl;
return;
}
Node* temp = head;
do {
cout << temp->data << " <-> ";
temp = temp->next;
} while (temp != head);
cout << "(head)" << endl;
}
Example Output:
List: 10 <-> 20 <-> (head)