Data Structure Unit 2 Notes
Data Structure Unit 2 Notes
Examples of abstract data type in data structures are List, Stack, Queue, etc.
Abstract Data Type Model
List ADT
Lists are linear data structures that hold data in a non-continuous structure. The list is made up of
data storage containers known as "nodes." These nodes are linked to one another, which means that
each node contains the address of another block. All of the nodes are thus connected to one another
via these links. You can discover more about lists in this article: Linked List Data Structure.
Some of the most essential operations defined in List ADT are listed below.
• front(): returns the value of the node present at the front of the list.
• back(): returns the value of the node present at the back of the list.
• push_front(int val): creates a pointer with value = val and keeps this pointer to the front of
the linked list.
• push_back(int val): creates a pointer with value = val and keeps this pointer to the back of
the linked list.
• size(): returns the number of nodes that are present in the list
Stack ADT
A stack is a linear data structure that only allows data to be accessed
from the top. It simply has two operations: push (to insert data to the
top of the stack) and pop (to remove data from the stack). (used to
remove data from the stack top).
Some of the most essential operations defined in Stack ADT are listed below.
• top(): returns the value of the node present at the top of the stack.
• push(int val): creates a node with value = val and puts it at the stack top.
• size(): returns the number of nodes that are present in the stack.
Queue ADT
A queue is a linear data structure that allows data to be accessed from both ends. There are two
main operations in the queue: push (this operation inserts data to the back of the queue) and pop
(this operation is used to remove data from the front of the queue).
Some of the most essential operations defined in Queue ADT are listed below.
• front(): returns the value of the node present at the front of the queue.
• back(): returns the value of the node present at the back of the queue.
• push(int val): creates a node with value = val and puts it at the front of the queue.
• size(): returns the number of nodes that are present in the queue
• Provides abstraction, which simplifies the complexity of the data structure and allows users
to focus on the functionality.
• Enables code reusability as the same data structure can be used in multiple programs with
the same interface.
• Promotes the concept of data hiding by encapsulating data and operations into a single unit,
which enhances security and control over the data.
• Supports polymorphism, which allows the same interface to be used with different
underlying data structures, providing flexibility and adaptability to changing requirements.
• Overhead: Using ADTs may result in additional overhead due to the need for abstraction and
encapsulation.
• Limited control: ADTs can limit the level of control that a programmer has over the data
structure, which can be a disadvantage in certain scenarios.
• Using Array
In a linked list-based implementation, the push operation is implemented by creating a new node
with the new element and setting the next pointer of the current top node to the new node. The pop
operation is implemented by setting the next pointer of the current top node to the next node and
returning the value of the current top node.
operations */
#include<iostream>
class Stack {
int top;
public:
int pop();
int peek();
bool isEmpty();
};
bool Stack::push(int x)
return false;
else {
a[++top] = x;
return true;
int Stack::pop()
if (top < 0) {
return 0;
else {
int x = a[top--];
return x;
int Stack::peek()
if (top < 0) {
return 0;
else {
int x = a[top];
return x;
}
}
bool Stack::isEmpty()
int main()
class Stack s;
s.push(10);
s.push(20);
s.push(30);
while(!s.isEmpty())
s.pop();
return 0;
}
//Code is Modified By Vinay Pandey
Output
Top element is : 20
• Easy to implement.
• It is not dynamic i.e., it doesn’t grow and shrink depending on needs at runtime. [But in case
of dynamic sized arrays like vector in C++, list in Python, ArrayList in Java, stacks can grow
and shrink with array implementation as well].
#include <bits/stdc++.h>
class StackNode {
public:
int data;
StackNode* next;
};
StackNode* newNode(int data)
stackNode->data = data;
stackNode->next = NULL;
return stackNode;
return !root;
stackNode->next = *root;
*root = stackNode;
if (isEmpty(*root))
return INT_MIN;
*root = (*root)->next;
free(temp);
return popped;
}
if (isEmpty(root))
return INT_MIN;
return root->data;
// Driver code
int main()
push(&root, 10);
push(&root, 20);
push(&root, 30);
while(!isEmpty(root))
pop(&root);
}
return 0;
Output
10 pushed to stack
20 pushed to stack
30 pushed to stack
Top element is 20
Output
10 pushed to stack
20 pushed to stack
30 pushed to stack
Top element is 20
• Simplicity: Stacks are a simple and easy-to-understand data structure, making them suitable
for a wide range of applications.
• Efficiency: Push and pop operations on a stack can be performed in constant time (O(1)) ,
providing efficient access to data.
• Last-in, First-out (LIFO): Stacks follow the LIFO principle, ensuring that the last element
added to the stack is the first one removed. This behavior is useful in many scenarios, such as
function calls and expression evaluation.
• Limited memory usage: Stacks only need to store the elements that have been pushed onto
them, making them memory-efficient compared to other data structures.
Disadvantages of Stack Data Structure:
• Limited access: Elements in a stack can only be accessed from the top, making it difficult to
retrieve or modify elements in the middle of the stack.
• Potential for overflow: If more elements are pushed onto a stack than it can hold, an
overflow error will occur, resulting in a loss of data.
• Not suitable for random access: Stack s do not allow for random access to elements, making
them unsuitable for applications where elements need to be accessed in a specific order.
• Limited capacity: Stacks have a fixed capacity, which can be a limitation if the number of
elements that need to be stored is unknown or highly variable.
• In Memory management, any modern computer uses a stack as the primary management
for a running purpose. Each program that is running in a computer system has its own
memory allocations.
• Stack also helps in implementing function call in computers. The last called function is always
completed first.
Explanation
• 1434 0
•
To convert infix expression to postfix expression, use the stack data structure. Scan the infix
expression from left to right. Whenever we get an operand, add it to the postfix expression and if we
get an operator or parenthesis add it to the stack by maintaining their precedence.
• If the precedence and associativity of the scanned operator are greater than the
precedence and associativity of the operator in the stack [or the stack is empty or
the stack contains a ‘(‘ ], then push it in the stack. [‘^‘ operator is right associative
and other operators like ‘+‘,’–‘,’*‘ and ‘/‘ are left-associative].
o Check especially for a condition when the operator at the top of the stack
and the scanned operator both are ‘^‘. In this condition, the precedence of
the scanned operator is higher due to its right associativity. So it will be
pushed into the operator stack.
o In all the other cases when the top of the operator stack is the same as the
scanned operator, then pop the operator from the stack because of left
associativity due to which the scanned operator has less precedence.
• Else, Pop all the operators from the stack which are greater than or equal to in
precedence than that of the scanned operator.
o After doing that Push the scanned operator to the stack. (If you encounter
parenthesis while popping then stop there and push the scanned operator in
the stack.)
5. If the scanned character is a ‘)’, pop the stack and output it until a ‘(‘ is encountered, and
discard both the parenthesis.
7. Once the scanning is over, Pop the stack and add the operators in the postfix expression until
it is not empty.
Illustration:
1st Step: Here i = 0 and exp[i] = ‘a’ i.e., an operand. So add this in the postfix expression. Therefore,
postfix = “a”.
Add ‘a’ in the postfix
2nd Step: Here i = 1 and exp[i] = ‘+’ i.e., an operator. Push this into the stack. postfix = “a” and stack =
{+}.
3rd Step: Now i = 2 and exp[i] = ‘b’ i.e., an operand. So add this in the postfix expression. postfix =
“ab” and stack = {+}.
4th Step: Now i = 3 and exp[i] = ‘*’ i.e., an operator. Push this into the stack. postfix = “ab” and stack
= {+, *}.
Push ‘*’ in the stack
5th Step: Now i = 4 and exp[i] = ‘c’ i.e., an operand. Add this in the postfix expression. postfix = “abc”
and stack = {+, *}.
6th Step: Now i = 5 and exp[i] = ‘+’ i.e., an operator. The topmost element of the stack has higher
precedence. So pop until the stack becomes empty or the top element has less precedence. ‘*’ is
popped and added in postfix. So postfix = “abc*” and stack = {+}.
Pop ‘*’ and add in postfix
Now top element is ‘+‘ that also doesn’t have less precedence. Pop it. postfix = “abc*+”.
7th Step: Now i = 6 and exp[i] = ‘d’ i.e., an operand. Add this in the postfix expression. postfix =
“abc*+d”.
Final Step: Now no element is left. So empty the stack and add it in the postfix expression. postfix =
“abc*+d+”.
Below is the implementation of the above algorithm:
#include <bits/stdc++.h>
int prec(char c) {
if (c == '^')
return 3;
return 2;
return 1;
else
return -1;
if (c == '^')
return 'R';
// to postfix expression
void infixToPostfix(string s) {
stack<char> st;
string result;
char c = s[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
result += c;
else if (c == '(')
st.push('(');
else if (c == ')') {
result += st.top();
st.pop();
// If an operator is scanned
else {
associativity(s[i]) == 'L') {
result += st.top();
st.pop();
st.push(c);
while (!st.empty()) {
result += st.top();
st.pop();
// Driver code
int main() {
// Function call
infixToPostfix(exp);
return 0;
Iterate the expression from left to right and keep on storing the operands into a stack. Once an
operator is received, pop the two topmost elements and evaluate them and push the result in the
stack again.
Illustration:
• Scan 3, again a number, push it to stack, stack now contains ‘2 3’ (from bottom to top)
Push 3 into stack
• Scan *, it’s an operator. Pop two operands from stack, apply the * operator on operands. We
get 3*1 which results in 3. We push the result 3 to stack. The stack now becomes ‘2 3’.
Evaluate * operator and push result in stack
• Scan +, it’s an operator. Pop two operands from stack, apply the + operator on operands. We
get 3 + 2 which results in 5. We push the result 5 to stack. The stack now becomes ‘5’.
Evaluate + operator and push result in stack
• Scan 9, it’s a number. So we push it to the stack. The stack now becomes ‘5 9’.
Push 9 into stack
• Scan -, it’s an operator, pop two operands from stack, apply the – operator on operands, we
get 5 – 9 which results in -4. We push the result -4 to the stack. The stack now becomes ‘-4’.
Evaluate ‘-‘ operator and push result in stack
• There are no more elements to scan, we return the top element from the stack (which is the
only element left in a stack).
Follow the steps mentioned below to evaluate postfix expression using stack:
• Scan the given expression from left to right and do the following for every scanned element.
o If the element is an operator, pop operands for the operator from the stack. Evaluate
the operator and push the result back to the stack.
• When the expression is ended, the number in the stack is the final answer.
Stack: A stack is a data structure in which elements are inserted and deleted only at one end called
the top of the stack. It follows the LIFO (Last In First Out) mechanism.
When a recursive function is invoked, its parameters are stored in a data structure called activation
records. Every time the recursive function is invoked, a new activation record is generated and stored
in the memory. These activation records are stored in the special stack called the recursive stack.
These activation records are deleted when the function execution is completed.
So, when a recursive function is invoked, it generates the activation records for different values of the
recursive function hence, extending the recursion stack size. When the recursive function execution
is completed one by one its activation records get deleted hence, contracting the recursive stack size.
The recursive stack size depends on the number of activation records created and deleted.
#include <bits/stdc++.h>
int fact(int n)
if (n == 1)
return 1;
int main()
int p;
p = fact(2);
return 0;
Time complexity: O(n)
Illustration:
For the above program. Firstly, the activation record for main stack is generated and stored in the
stack.
Initial state
In the above program, there is a recursive function fact that has n as the local parameter. In the
above example program, n=2 is passed in the recursive function call.
First Step: First, the function is invoked for n =2 and its activation record are created in the recursive
stack.
1st step
2nd Step: Then according to the recursive function, it is invoked for n=1 and its activation record is
created in the recursive stack.
2nd step
3rd Step: After the execution of the function for value n=1 as it is a base condition, its execution gets
completed and its activation record gets deleted.
3rd step
4th step: Similarly, the function for value n=2(its previous function) gets executed and its activation
record gets deleted. It comes out from the recursive function to the main function.
4th step
So, in the above example for recursive function fact and value, n=2 recursive stack size excluding the
main function is 2. Hence, for value n recursive stack size is n.
A Queue Data Structure is a fundamental concept in computer science used for storing and
managing data in a specific order. It follows the principle of “First in, First out” (FIFO), where the first
element added to the queue is the first one to be removed. Queues are commonly used in various
algorithms and applications for their simplicity and efficiency in managing data flow.
What is Queue in Data Structures?
A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. It operates like a
line where elements are added at one end (rear) and removed from the other end (front).
• Dequeue (Delete): Removes and returns the element from the front of the queue.
• Peek: Returns the element at the front of the queue without removing it.
Applications of Queue
Implementation of Queues
•
•
Please note that a simple array implementation discussed here is not used in practice as it is not
efficient. In practice, we either use Linked List Implementation of Queue or circular array
implementation of queue. The idea of this post is to give you a background as to why we need a
circular array implementation.
• take two variables front and rear which are initialized as 0 and -1 respectively
• rear is the index up to which the elements are stored in the array including the rear index
itself. We mainly add an item by incrementing it.
• front is the index of the first element of the array. We mainly remove the element at this
index in Dequeue operation.
• Enqueue: Addition of an element to the queue. Adding an element will be performed after
checking whether the queue is full or not. If rear == capacity-1, then it is said to be an
Overflow condition as the array is full. If array is not full. then store the element at arr[rear]
and increment rear by 1 .
• Dequeue: Removal of an element from the queue. An element can only be deleted when
there is at least an element to delete. If rear == -1, then it is said to be an Underflow
condition as the array is empty. If the element at arr[front] can be deleted then move all the
remaining elements to the left by one position in order to maintain the FIFO (the first element
must be deleted).
• Front: Get the front element from the queue i.e. arr[front] if the queue is not empty.
• Display: Print all elements of the queue. If the queue is non-empty, traverse and print all the
elements from the index front to rear.
Below is the implementation of a queue using an array:
#include <bits/stdc++.h>
struct Queue {
int* queue;
Queue(int c)
front = 0;
rear = -1;
capacity = c;
if (rear == capacity - 1) {
printf("\nQueue is full\n");
return;
queue[++rear] = data;
// of the queue
void queueDequeue()
printf("\nQueue is empty\n");
return;
}
// Shift all elements from index 1 till rear to
// Decrement rear
rear--;
void queueDisplay()
printf("\nQueue is Empty\n");
return;
printf("\n");
void queueFront()
if (rear == -1) {
printf("\nQueue is Empty\n");
return;
}
};
// Driver code
int main(void)
Queue q(4);
q.queueDisplay();
q.queueEnqueue(20);
q.queueEnqueue(30);
q.queueEnqueue(40);
q.queueEnqueue(50);
q.queueDisplay();
q.queueEnqueue(60);
q.queueDisplay();
// Dequeue elements
q.queueDequeue();
q.queueDequeue();
q.queueDisplay();
q.queueEnqueue(60);
q.queueDisplay();
q.queueFront();
return 0;
Output
Queue is Empty
Queue is full
40 <-- 50 <--
Front Element...
Queue – Linked List Implementation
In this article, the Linked List implementation of the queue data structure is discussed and
implemented. Print ‘-1’ if the queue is empty.
we maintain two pointers, front, and rear. The front points to the first item of the queue and rear
points to the last item.
• enQueue(): This operation adds a new node after the rear and moves the rear to the next
node.
• deQueue(): This operation removes the front node and moves the front to the next node.
• Create a class QNode with data members integer data and QNode* next
• Create a class Queue with data members QNode front and rear
o If the rear is set to NULL then set the front and rear to temp and return(Base Case)
o Else set rear next to temp and then move rear to temp
• Dequeue Operation:
o Initialize QNode temp with front and set front to its next
// linked list
#include <bits/stdc++.h>
class Node {
public:
int data;
Node* next;
Node(int new_data)
this->data = new_data;
this->next = nullptr;
};
class Queue {
public:
bool isEmpty()
if (front == nullptr) {
return true;
return false;
}
// and rear
if (this->isEmpty()) {
return;
// change rear
rear->next = new_node;
rear = new_node;
void dequeue() {
if (this->isEmpty()) {
return;
front = front->next;
// to nullptr
if (front == nullptr)
rear = nullptr;
delete temp;
int getFront() {
if (this->isEmpty()) {
return INT_MIN;
return front->data;
int getRear() {
if (this->isEmpty()) {
return INT_MIN;
}
return rear->data;
};
int main()
Queue q;
q.enqueue(10);
q.enqueue(20);
q.dequeue();
q.dequeue();
q.enqueue(30);
q.enqueue(40);
q.enqueue(50);
q.dequeue();
// Display the front and rear elements of the queue
cout << "Queue Rear: " << q.getRear() << endl << endl;
return 0;
Output
Queue Front: 10
Queue Rear: 20
Queue Front: 40
Queue Rear: 50
A circular queue is the extended version of a regular queue where the last element is connected to
the first element. Thus forming a circle-like structure.
The circular queue solves the major limitation of the normal queue. In a normal queue, after a bit of
insertion and deletion, there will be non-usable empty space.
Limitation of the regular Queue
Here, indexes 0 and 1 can only be used after resetting the queue (deletion of all elements). This
reduces the actual size of the queue.
Circular Queue works by the process of circular increment i.e. when we try to increment the pointer
and we reach the end of the queue, we start from the beginning of the queue.
Here, the circular increment is performed by modulo division with the queue size. That is,
1. Enqueue Operation
• circularly increase the REAR index by 1 (i.e. if the rear reaches the end, next it would be at
the start of the queue)
2. Dequeue Operation
However, the check for full queue has a new additional case:
The second case happens when REAR starts from 0 due to circular increment and when its value is
just 1 less than FRONT, the queue is full.
Enque and Deque Operations
Circular Queue Implementations in Python, Java, C, and C++
The most common queue implementation is using arrays, but it can also be implemented using lists.
#include <iostream>
class Queue {
private:
public:
Queue() {
front = -1;
rear = -1;
bool isFull() {
return true;
return true;
return false;
if (front == -1)
return true;
else
return false;
// Adding an element
if (isFull()) {
} else {
items[rear] = element;
// Removing an element
int deQueue() {
int element;
if (isEmpty()) {
return (-1);
} else {
element = items[front];
if (front == rear) {
front = -1;
rear = -1;
else {
return (element);
void display() {
int i;
if (isEmpty()) {
} else {
};
int main() {
Queue q;
q.enQueue(1);
q.enQueue(2);
q.enQueue(3);
q.enQueue(4);
q.enQueue(5);
q.enQueue(6);
q.display();
if (elem != -1)
q.display();
q.enQueue(7);
q.display();
q.enQueue(8);
return 0;
}
Circular Queue Data Structure
A circular queue is the extended version of a regular queue where the last element is connected to
the first element. Thus forming a circle-like structure.
The circular queue solves the major limitation of the normal queue. In a normal queue, after a bit of
insertion and deletion, there will be non-usable empty space.
Here, indexes 0 and 1 can only be used after resetting the queue (deletion of all elements). This
reduces the actual size of the queue.
Circular Queue works by the process of circular increment i.e. when we try to increment the pointer
and we reach the end of the queue, we start from the beginning of the queue.
Here, the circular increment is performed by modulo division with the queue size. That is,
1. Enqueue Operation
• circularly increase the REAR index by 1 (i.e. if the rear reaches the end, next it would be at
the start of the queue)
2. Dequeue Operation
• for the last element, reset the values of FRONT and REAR to -1
However, the check for full queue has a new additional case:
The second case happens when REAR starts from 0 due to circular increment and when its value is
just 1 less than FRONT, the queue is full.
Enque and Deque Operations
Circular Queue Implementations in Python, Java, C, and C++
The most common queue implementation is using arrays, but it can also be implemented using lists.
Python
Java
C++
#include <iostream>
class Queue {
private:
public:
Queue() {
front = -1;
rear = -1;
bool isFull() {
return true;
return true;
}
return false;
bool isEmpty() {
if (front == -1)
return true;
else
return false;
// Adding an element
if (isFull()) {
} else {
items[rear] = element;
// Removing an element
int deQueue() {
int element;
if (isEmpty()) {
return (-1);
} else {
element = items[front];
if (front == rear) {
front = -1;
rear = -1;
else {
return (element);
void display() {
int i;
if (isEmpty()) {
} else {
};
int main() {
Queue q;
q.deQueue();
q.enQueue(1);
q.enQueue(2);
q.enQueue(3);
q.enQueue(4);
q.enQueue(5);
q.enQueue(6);
q.display();
if (elem != -1)
q.display();
q.enQueue(7);
q.display();
q.enQueue(8);
return 0;
The complexity of the enqueue and dequeue operations of a circular queue is O(1) for (array
implementations).
• CPU scheduling
• Memory management
• Traffic Management
Priority Queue
A priority queue is a special type of queue in which each element is associated with a priority value.
And, elements are served on the basis of their priority. That is, higher priority elements are served
first.
However, if elements with the same priority occur, they are served according to their order in the
queue.
Generally, the value of the element itself is considered for assigning the priority. For example,
The element with the highest value is considered the highest priority element. However, in other
cases, we can assume the element with the lowest value as the highest priority element.
In a queue, the first-in-first-out rule is implemented whereas, in a priority queue, the values are
removed on the basis of priority. The element with the highest priority is removed first.
Priority queue can be implemented using an array, a linked list, a heap data structure, or a binary
search tree. Among these data structures, heap data structure provides an efficient implementation
of priority queues.
Hence, we will be using the heap data structure to implement the priority queue in this tutorial. A
max-heap is implemented in the following operations. If you want to learn more about it, please
visit max-heap and min-heap.
Basic operations of a priority queue are inserting, removing, and peeking elements.
Before studying the priority queue, please refer to the heap data structure for a better understanding
of binary heap as it is used to implement the priority queue in this article.
Inserting an element into a priority queue (max-heap) is done by the following steps.
If there is no node,
create a newNode.
else (a node is already present)
insert the newNode at the end (last node from left to right.)
For Min Heap, the above algorithm is modified so that parentNode is always smaller than newNode.
remove noteToBeDeleted
For Min Heap, the above algorithm is modified so that the both childNodes are smaller
than currentNode.
return rootNode
Extract-Max returns the node with maximum value after removing it from a Max Heap whereas
Extract-Min returns the node with minimum value after removing it from Min Heap.
#include <iostream>
#include <vector>
*b = *a;
*a = temp;
// Find the largest among root, left child and right child
int largest = i;
int l = 2 * i + 1;
int r = 2 * i + 2;
largest = r;
if (largest != i) {
swap(&hT[i], &hT[largest]);
heapify(hT, largest);
if (size == 0) {
hT.push_back(newNum);
} else {
hT.push_back(newNum);
heapify(hT, i);
int i;
if (num == hT[i])
break;
}
hT.pop_back();
heapify(hT, i);
// Driver code
int main() {
vector<int> heapTree;
insert(heapTree, 3);
insert(heapTree, 4);
insert(heapTree, 9);
insert(heapTree, 5);
insert(heapTree, 2);
printArray(heapTree);
deleteNode(heapTree, 4);
cout << "After deleting an element: ";
printArray(heapTree);
• Dijkstra's algorithm
Deque or Double Ended Queue is a type of queue in which insertion and removal of elements can
either be performed from the front or the rear. Thus, it does not follow FIFO rule (First In First Out).
Representation of Deque
Types of Deque
Operations on a Deque
Below is the circular array implementation of deque. In a circular array, if the array is full, we start
from the beginning.
But in a linear array implementation, if the array is full, no more elements can be inserted. In each of
the operations below, if the array is full, "overflow message" is thrown.
Before performing the following operations, these steps are followed.
2. If the deque is full (i.e. (front == 0 && rear == n - 1) || (front == rear + 1)), insertion operation
cannot be performed (overflow condition).
3. If the deque is empty, reinitialize front = 0. And, add the new key into array[front].
3. If the deque is empty, reinitialize rear = 0. And, add the new key into array[rear].
2. If the deque is empty (i.e. front = -1), deletion cannot be performed (underflow condition).
3. If the deque has only one element (i.e. front = rear), set front = -1 and rear = -1.
4. Else if front is at the last index (i.e. front = n - 1), set front = 0.
2. If the deque is empty (i.e. front = -1), deletion cannot be performed (underflow condition).
3. If the deque has only one element (i.e. front = rear), set front = -1 and rear = -1, else follow
the steps below.
5. Check Empty
This operation checks if the deque is empty. If front = -1, the deque is empty.
6. Check Full
This operation checks if the deque is full. If front = 0 and rear = n - 1 OR front = rear + 1, the deque is
full.
#include <iostream>
#define MAX 10
class Deque {
int arr[MAX];
int front;
int rear;
int size;
public:
Deque(int size) {
front = -1;
rear = 0;
this->size = size;
void deletefront();
void deleterear();
bool isFull();
bool isEmpty();
int getFront();
int getRear();
};
bool Deque::isFull() {
bool Deque::isEmpty() {
}
void Deque::insertfront(int key) {
if (isFull()) {
<< endl;
return;
if (front == -1) {
front = 0;
rear = 0;
else if (front == 0)
front = size - 1;
else
front = front - 1;
arr[front] = key;
if (isFull()) {
return;
if (front == -1) {
front = 0;
rear = 0;
}
rear = 0;
else
rear = rear + 1;
arr[rear] = key;
if (isEmpty()) {
<< endl;
return;
if (front == rear) {
front = -1;
rear = -1;
front = 0;
else
front = front + 1;
void Deque::deleterear() {
if (isEmpty()) {
return;
if (front == rear) {
front = -1;
rear = -1;
} else if (rear == 0)
rear = size - 1;
else
rear = rear - 1;
int Deque::getFront() {
if (isEmpty()) {
<< endl;
return -1;
return arr[front];
int Deque::getRear() {
<< endl;
return -1;
return arr[rear];
}
int main() {
Deque dq(4);
dq.insertrear(5);
dq.insertrear(11);
dq.deleterear();
cout << "after deletion of the rear element, the new rear element: " << dq.getRear() << endl;
dq.insertfront(8);
dq.deletefront();
cout << "after deletion of front element new front element: " << dq.getFront() << endl;