Stack and Queue Presentation New
Stack and Queue Presentation New
Stack and Queue Presentation New
By Zelalem Kassahun
Data in the stack are placed or removed in the principle of Last In First Out (LIFO). All insertions and deletions
are permitted only at one end of the list.
Stacks make excellent mechanisms for temporary storage of information within procedures.
Stacks can be implemented in two ways, first where underlying data storage is an array and second where
underlying storage is linked list.
Stack implementation using array:
To implement the stack using array, we need to keep track of the topmost element in the array.
Operations On A Stack:
All the operations regarding the stack are performed using arrays.
1. Push Operation
The push operation is used to insert an element into the stack. The new element is added at the topmost
position of the stack.
Firstly, To define(create) array of stack data structure :
int stack[SIZE]; // creates a stack of integer, Where SIZE is the maximum capacity of stack
declare a variable top to keep track of top element on the stack and with initialized empty stack:
unsigned int top = -1; // there are no elements in stack
Create a PUSH function which the insertion of new element on the stack.
Declare the variable data which inserted new element on the stack:
int item;
To insert a new element on stack, first to check whether the stack is full or not. If the condition (top=SIZE–1)
is true, the stack is full then an OVERFLOW message is printed and exit.
If the stack is not full, increments top to point the next empty space and add new element at the top pointing
on stack position:
top++;
stack[top] = data; // Push data in stack
2. Pop Operation
The pop operation is used to delete the topmost element from the stack.
Create a POP function which the deletion of the top most element on the stack.
To delete the topmost element, first to check whether the stack is empty or not, if the condition (top == -1) is
true, the stack is empty then an UNDERFLOW message is printed and exit.
If the stack is not empty, then to check whether the stack has contain only one element or more elements. If the
condition (top == 0) is true, decrements the value pointed by top pointer on memory space and delete the
topmost element from the stack:
top= -1;
If the stack is contain more than one elements, decrements the value pointed by top pointer on memory space:
top = top - 1;
3. Peek Operation
Peek is an operation that returns the value of the topmost element of the stack without deleting it from the
stack.
Create a Peek function which display the topmost element on the stack.
To display the topmost element, first to check whether the stack is empty or not. If the condition (top == -1) is
true, the stack is empty then an UNDERFLOW message is printed and exit.
If the stack is not empty, traverse and display the elements of stack:
for(i=top;i>=0;i--)
{
printf("\n%d\n",stack[i]);
}
Stack implementation using linked list:
In stack Implementation, a stack contains a top pointer. which is “head” of the stack where pushing and
popping items happens at the head of the list.
stack implemented using linked list works for the variable size of data. So, there is no need to fix the size at the
beginning of the implementation.
In linked list implementation of stack, the nodes are maintained non-contiguously in the memory. Each node
contains a pointer to its immediate successor node in the stack.
Stack Operations using Linked List
1. push operation:
First, to define(create) stack node structure:
struct node
{
int data;
struct node*next;
};
Declare a node type variable(top )which used to store address of the top most node of stack:
struct node *top ;
Create a push function which the insertion of new element on the stack.
Declare the variable data which inserted new data on the stack:
int data;
Create(declare) a new node variable(newNode) and allocate the space to new node :
struct node *newNode;
newNode = (struct node *) malloc(sizeof(struct node*));
Check whether the newNode is empty or not. If the condition (newNode== NULL) is true, the newNode node is
empty then unable to insert the newNode node on stack then an APPROPRIATE message is printed and exit.
Check whether the stack is empty or not. If the condition (top== NULL) is true, store data value into the data
part of the node and a new node make sure that the address part of the new node points to NULL :
newNode -> data = data; // Assign data value to newly created node
newNode->next=NULL;
To make the newNode node as top node:
top = newNode;
If the stack is not empty, store data value into the data part of the node and link new node with the current
stack top most node:
newNode->data = data;
newNode->next = top;
Create a Peek function which display the topmost element on the stack
To display the topmost element, first check whether the stack is empty or not. If the condition (top == NULL)
is true, the stack is empty then an UNDERFLOW message is printed and exit.
If the stack is not empty, declare a temporary node type variable(temp) in order to traverse the list of stack:
struct node *temp;
Make the temp node as top node:
temp = top;// Initialize the temp node to top node
To traverse the list of stack by using the temp node and display the list of stack:
while(temp!= NULL)
{
printf("%d\n",temp->data);
temp = temp->next;
}
Application Of Stacks
Stacks are useful for any application requiring LIFO storage.
1. Evaluation of arithmetic expressions
the arithmetic operation which is a high level programming language is converted into machine language. This
is because machine can understand only binary language (0 and 1).
computers work more efficiently with expressions written using prefix and postfix notations. prefix and
postfix notation is easier to parse for a machine.
To write expressions using infix notation easy to read for humans, but computers find it difficult to parse as
the computer needs a lot of information to evaluate the expression.
Conversion of infix to postfix expression and Computation to postfix (reverse polish) expression.
Infix, postfix, and prefix notations are three different but equivalent notations of writing algebraic expressions.
In postfix notation, the operator is placed after the operands. Example AB+C*
In a prefix notation, the operator is placed before the operands. Example *+ABC
Recursion
Recursion is a technique that breaks a problem into one or more sub-problems that are similar to
the original problem.
A recursive function is defined as a function that calls itself to solve a smaller version of its task until a final
call is made.
A recursive function is a function that calls itself until a “base condition” is true, and execution stops.
A recursive function makes use of the system stack to temporarily store the return address and local variables
of the calling function.
Any recursive function can be characterized based on:
1. whether the function calls itself directly or indirectly (direct or indirect recursion)
2. whether any operation is pending at each recursive call (tail recursive or not), and
A function is said to be indirectly recursive if it contains a call to another function which ultimately calls it.
int Func (int n){
if (n == 0)
return n;
else
return Func2 (n);}
int Func2(int x){
return Func(x-1);}
Queue
Queue is a linear data structure where elements are ordered in special fashion.
A queue is a collection of objects that are added and removed based on the first-in-first-out (FIFO) principle.
It means that the first element added to the queue will be the first one to be removed from the queue.
The elements in a queue are added at one end called the REAR and removed from the other end called the
FRONT.
The basic operations which can be performed on queue:
1. Enqueue() function is used to insert new elements into the end of queue.
2. Dequeue() function is used to remove an element from the front of queue.
3. Peek() function is used to get the front element of queue , without removing it.
4. isFull(): check if queue is full.
5. isEmpty(): check if queue is empty.
Queue can be implemented in two ways, by using arrays or linked lists.
Queue implementation using array:
In array implementation, the queue is formed by using the array. All the operations regarding the stack are
performed using arrays.
Operations On Queue:
1. Enqueue Operation
Enqueue is the process of inserting an element to queue.
First, To create(declere) queue data structure using array:
int queue[max_size]; // creates a queue of integer, Where max_size is the maximum capacity of queue
Declare a variable rear which Points at the index where the next insertion will be performed and initialize
with -1:
unsigned int rear = - 1; // Initially it is indexed to last element of queue
Declare a variable front which Points at the index where the next deletion will be performed and initialize
with -1:
unsigned int front = - 1; // Initially it is indexed to first element of queue
Create a Enqueue function which the insertion of new element on queue.
Declare the variable data which inserted new element on queue:
int data;
To insert a new element on queue, first to check whether the queue is full or not. If the condition (rear ==
max_size-1 ) is true, the queue is full then an OVERFLOW message is printed and exit.
If the queue is not full, then to check whether the queue is empty or not. If the condition (front == -1 &&
rear == -1) is true, increment both rear and front points on queue position then insert the first element on
queue:
rear++;
front++;
queue[rear] = data;
If the queue is not empty, increments rear to point next empty space and add new element at the rear
pointing at queue position :
rear++;
queue[rear] = data;
2. Dequeue Operation
Dequeue is the process of removing an element from queue.
Create a Dequeue function which the deletion of the front element on queue.
To delete front element on queue, first to check the queue is empty or not, if the condition (front == -1 || front
> rear) is true, the queue is empty then an UNDERFLOW message is printed and exit.
If queue is not empty, then to check the queue has contain only one element or more elements. If the condition
(front == rear) is true, decrement the value pointed by both rear and front pointers on memory space then
delete the front pointing element from queue:
front = -1;
rear = -1;
If the queue is contain more than one elements, Increments the value pointed by front pointer on memory
space:
front = front + 1;
3. Peek Operation
Peek is an operation that returns either the values of the front or rear elements of the queue without
deleting it from the queue.
Create a Peek function which display the front element on queue.
To display the front element, first check whether the queue is empty or not. If the condition is rear == -1
is true, an UNDERFLOW message is printed and exit.
If the queue is not empty, then traverse and display the elements of queue:
for(i=front;i<=rear;i++){
printf("\n%d\n",queue[i]);}
Queue implementation using linked list:
There are two basic operations which can be implemented on the linked queues. The operations are Insertion
and Deletion.
Before do any operations on queue, firstly, to define(create) a queue node structure.
struct node {
int data; //data is the data you want to store in queue
struct node * next; // the *next will store location of next node if exists otherwise NULL
};
Declare node type variables(front and rear),which front used to store the address of the first element of the
queue and rear used to store the address of the last element of the queue:
struct node *front, * rear ;
Operations On A Linked List Queue:
1. Enqueue Operation:
The insert operation append the queue by adding an element to the end of the queue. The new element will be
the last element of the queue.
Create enqueue function which the insertion of new element on queue.
Declare the variable data which inserted new element on queue:
int data;
Create(declare) a new node variable(newNode) and allocate the space to new node :
struct node *newNode;
newNode = (struct node *) malloc (sizeof(struct node));
Check whether the newNode is empty or not. If the condition (newNode== NULL) is true, the newNode node
is empty then unable to insert the newNode node on queue then an APPROPRIATE message is printed and
exit.
If the newNode is not empty, store value into the data part of the new node:
newNode->data = data;// Assign data value to newly created node
Check whether the queue is empty or not. If the condition (front== NULL) is true, the new element will be
added on queue. To make the new node as the front and rear nodes:
front = newNode;
rear = newNode;
Make the next pointer of front and rear nodes will point to NULL:
front->next = NULL;
rear->next = NULL;
If the queue is not empty, The next pointer of rear node will point to the new node:
rear->next = newNode;
To make the new node as rear node:
rear = newNode;
Make sure that the next address field of the rear node must point to NULL:
rear->next = NULL;
2. Dequeue Operation
Create dequeue function which deletion of the first element on queue.
Before dequeue, first check whether the queue is empty or not. If the condition (front == NULL) is true,
an UNDERFLOW message is printed and exit.
If the queue is not empty, then declare node type variable temp:
struct node *temp;
To make the temp node as front node:
temp = front; // Initialize the temp node to front node
Shift the front node into point to its next node:
front = front -> next; // shift the next node from front node
Free the memory occupied by the temp node:
free(temp); // Delete the temp node
3. Peek Operation
Create Peek function which display the list of element on queue.
To display the list of element, first check whether the queue is empty or not. If the condition (front == NULL)
is true, an UNDERFLOW message is printed and exit.
If the queue is not empty, to declare node type variable temp:
struct node *temp;
To make the temp node as front node:
temp = front; // Initialize the temp node to front node
To traverse the list of element on queue by using the temp node and display the list of element on queue:
while(temp!= NULL)
{
printf("\n%d\n", temp -> data);
temp = temp -> next;
}
Circular Queues
In linear queue, there can't be inserted any more element due to the condition (rear == max – 1) becomes
true.
Even if we delete some elements at the front end of the queue, we still can not insert any element since the
condition rear = max -1 still holds. This is simply the memory wastage.
To resolve this problem, to use a circular queue.
A circular queue is a linear data structure in which the operations are performed based on FIFO (First In First
Out) principle and the last position is connected back to the first position to make a circle.
Circular queue is also called ring buffer.
Circular array list fallows the First In First Out principle. Elements are added at the rear end and the elements
are deleted at the front end of the queue.
Circular queue will be full only when front = -1 and rear = max-1.
Circular queue can be implemented in two ways, by using arrays or linked. lists.
Circular Queue implementation using array:
Operations On A Circular Queue:
1. Enqueue Operation:
First, To create(declere) circular queue data structure using array:
int queue[max_size]; // creates a queue of integer, Where max_size is the maximum capacity of
queue
Declare a variable rear which Points at the index where the next insertion will be performed and initialize
with -1:
int rear = - 1; // Initially it is indexed to last element of queue
Declare a variable front which Points at the index where the next deletion will be performed and initialize
with -1:
int front = - 1; // Initially it is indexed to first element of queue
Create enqueue function which the insertion of new element on circular queue.
Declare the variable data which inserted new element on circular queue:
int data;
To insert a new element on circular queue, first to check whether the queue is full or not. If the condition
((rear+1)%max_size == front) is true, the queue is full then an OVERFLOW message is printed and exit.
If the queue is not full, to check whether the queue is empty or not. If the condition (front == -1 && rear ==
-1) is true, increment both rear and front points on queue position and insert the first element on queue:
rear++;
front++;
queue[rear] = data;
If the queue is not empty, then to check the rear is pointing to maximum array size of queue but the queue is
not full. If the condition (rear == max_size -1 && front != 0) is true, set the value of rear to 0 and insert the
new element on queue:
rear = 0; //
queue[rear] = data;
If the rear is not pointing to the maximum array size of queue, Increment rear points on queue position and
insert the new element:
rear = (rear+1)%max_size;
queue[rear] = data;
2. Dequeue Operation
Create a Dequeue function which the deletion of the front element from circular queue.
To delete front element on queue, first to check the queue is empty or not, if the condition ((front == -1 &&
rear == -1) is true, the queue is empty then an UNDERFLOW message is printed and exit.
If queue is not empty, then to check the queue has contain only one element or more elements. If the condition
(front == rear) is true, decrement the value both rear and front pointed to on memory space then delete the
front pointing element from queue:
front = -1;
rear = -1;
If the queue is contain more than one element, to check the front is pointing to maximum array size of queue.
If the condition (front == max_size – 1) is true, set the value of front to 0 then delete the front pointing element
from queue:
front = 0;
If the front is not pointing to the maximum array size of queue, Increment front points on queue position then
delete the front pointing element from queue:
front = front + 1;
3. Peek Operation
Create a Peek function which display the front element on circular queue.
Declare the variable i which use traverse the queue:
int i;
To display the front element, first check whether the queue is empty or not. If the condition is rear == -1 is
true, an UNDERFLOW message is printed and exit.
If the queue is not empty, then to check the front points to the queue size less than or equal to rear points to
the queue size. If the condition (front <= rear) is true, traverse and display the elements of queue:
while(i <= rear)
printf("%d\n",queue[i++]);
The front index is greater than rear index, traverse and display the elements of queue:
while(i <= max_size - 1)
printf("%d\n", queue[i++]);
i = 0;
while(i <= rear)
printf("%d\n",queue[i++]);
Deques
A deque (double-ended queue ) is a more generalized form of queue data structure in which the elements can
be insertion and deletion operations are performed at both ends (front and rear).
Double Ended Queue can be represented in TWO ways:
1. Input restricted deque: the insertion operation is performed at only one end and deletion operation is
performed at both ends. Enqueue_left(), Dequeue_left() and Dequeue_right()
2. Output restricted deque: the deletion operation is performed at only one end and insertion operation is
performed at both the ends. Enqueue_right(), Enqueue_left() and Dequeue_right().
In the computer’s memory, a deque is implemented using either a circular array or a circular doubly linked
list.
It is a head-tail linked list because elements can be added to or removed from either the front (head) or the
back (tail) end.
In a deque, left and right pointers, which point to either end of the deque.
Create Enqueue_right function which the insertion of new element on the right of circular queue.
Declare the variable data which inserted new element on circular queue:
int data;
To insert a new element on the right of circular queue, first to check whether the queue is full or not. If the
condition ((rear+1)%max_size == front ) is true, the queue is full then an OVERFLOW message is printed
and exit.
If the circular queue is not full, then to check whether the queue is empty or not. If the condition (front == -1
&& rear == -1) is true, increment both rear and front points on circular queue position then insert the first
element on the right of circular queue:
rear++;
front++;
queue[rear] = data;
If the circular queue is not empty, then to check rear points maximum array size and the front is not point the
first element on queue. If the condition (rear == max_size -1 && front != 0) is true, increments rear to
point the first empty space of the queue and add new element at the rear pointing at queue position:
rear = 0;
queue[rear] = data;
If the queue is not empty and the rear is not point the maximum size of queue, increments rear to point
next empty space and add new element at the rear pointing at queue position :
rear = (rear+1)%max_size;
queue[rear] = data;
2. Enqueue_left operation
Create Enqueue_left function which the insertion of new element on the left of circular queue.
Declare the variable data which inserted new element on circular queue:
int data;
To insert a new element on the left of circular queue, first to check whether the queue is full or not. If the
condition ((rear+1)%max_size == front ) is true, the queue is full then an OVERFLOW message is printed
and exit.
If the circular queue is not full, then to check whether the queue is empty or not. If the condition (front ==
-1 && rear == -1) is true, increment both rear and front points on circular queue position then insert the
first element on the left of circular queue:
rear++;
front++;
queue[front] = data;
If the circular queue is not empty, then to check front points the first element on queue and the rear is not point
the maximum size of queue. If the condition (front == 0 && rear != max_size -1) is true, increments front to
point the last empty space of the queue and add new element at the front pointing at queue position:
front = maxsize -1;
queue[front] = data;
If the queue is not empty and the front is not point the first element of queue, decrements front to point the
previous empty space and add new element at the front pointing at queue position :
front = (front - 1)%max_size;
queue[front] = data;
2 . Dequeue Operation
1. Dequeue_left operation
Create a Dequeue_left function which the deletion of the front element(left) on queue.
To delete front element on queue, first to check the queue is empty or not, if the condition (front == -1 &&
rear == -1) is true, the queue is empty then an UNDERFLOW message is printed and exit.
If queue is not empty, then to check the queue has contain only one element or more elements. If the condition
(front == rear) is true, decrement the value pointed by both rear and front pointers on memory space then
delete the front pointing element from queue:
front = -1;
rear = -1;
If the queue is contain more than one elements, then to check the front points to maximum array size element
on queue. If the condition (front == maxsize -1) is true, the front pointer points on the first element of queue:
front = 0;
If the queue is contain more than one elements and the front is not point to maximum array size element on
queue, Increments the value pointed by front pointer on the next element on queue:
front = front + 1;
2. Dequeue_right operation
Create a Dequeue_right function which the deletion of the last element(right) on queue.
To delete rear element on queue, first to check the queue is empty or not, if the condition (front == -1 && rear
== -1) is true, the queue is empty then an UNDERFLOW message is printed and exit.
If queue is not empty, then to check the queue has contain only one element or more elements. If the condition
(front == rear) is true, decrement the value pointed by both rear and front pointers on memory space then
delete the rear pointing element from queue:
front = -1;
rear = -1;
If the queue is contain more than one elements, then to check the rear points to the first element on queue. If
the condition (rear == 0) is true, the rear pointer points to maximum array size element of queue:
rear = max_size – 1;
If the queue is contain more than one elements and the rear is not point to the first element on queue,
Decrements the value pointed by rear pointer on the next element on queue:
rear = rear - 1;
priority queue
A priority queue is a special type of queue in which each element is associated with a priority and is served
according to its priority.
The general rules of processing the elements of a priority queue are:
1. An element with higher priority is processed before an element with a lower priority(An element with
high priority is dequeued before an element with low priority).
2. Two elements with the same priority are processed on a first-come-first-served (FCFS) basis
Priority queue can be implemented using an array, a linked list.
Data compression : It is used in Huffman codes which is used to compresses data.
Operating systems: It is also use in Operating System for load balancing (load balancing on server), interrupt handling.
Implementation Of Priority Queue Using Array:
Operations On Priority queue:
1. Enqueue Operation
First, To create(declere) a priority queue data structure using array:
int Peque[max_size]; // creates a deque of integer, Where max_size is the maximum capacity of
queue
Declare a variable rear which Points at the index where the next insertion will be performed and initialize
with -1:
unsigned int rear = - 1; // Initially it is indexed to last element of queue
Declare a variable front which Points at the index where the next deletion will be performed and initialize
with -1:
unsigned int front = - 1; // Initially it is indexed to first element of queue
Create Penqueue function which the insertion of new element with given priority to queue.
Declare the variable data which inserted new element on priority queue:
int data;
To insert a new element on the priority queue, first to check whether the queue is full or not. If the condition
(rear == max_size-1) is true, the queue is full then an OVERFLOW message is printed and exit.
If the priority queue is not full, then to check whether the queue is empty or not. If the condition (front == -1
&& rear == -1) is true, increment both rear and front points on priority queue position then insert the first
element on the priority queue:
rear++;
front++;
queue[rear] = data;
If the priority queue is not empty, then check when the data inserted greater than existing data, add new
element at the rear pointing at queue position and increments rear to point next empty space:
check(item);
rear++
2. Check Operation
Create Check function which compere the insertion of new element and existing elements on the priority
queue.
To Compare the insertion of new element and existing elements, traversing existing elements:
for (i = 0; i <= rear; i++)
{
if (data >= Pqueue[i])
{
for (j = rear + 1; j > i; j--)
{
Pqueue[j] = Pqueue[j - 1];
}
Finally, then insert the first element on the priority queue:
Priority_queue[i] = data;
3. Dequeue Operation
Create a Dequeue function which the deletion of the highest priority of element from queue.
Before deletion of element from priority queue, we check the queue is empty or not. If the condition (front ==
-1 && rear == -1) is true, an UNDERFLOW message is printed and exit.
If priority queue is not empty, then to check the queue has contain only one element or more elements. If the
condition (front == rear) is true, decrement the value pointed by both rear and front pointers on memory
space then delete the front pointing element from queue:
front = -1;
rear = -1;
If the priority queue is contain more than one elements, traverse and check match you want to delete element
and existing elements on priority queue and decrements the value pointed by rear pointer on the next element
on queue:
for (int i = 0; i <= rear; i++){
if ( item == Pqueue[i]){
for (; i < rear; i++){
Pqueue[i] = Pqueue[i + 1];}
rear = rear - 1;}}
4. Peek Operation
Peek is an operation that returns either the values of the front or rear elements of the queue without
deleting it from the queue.
Create a Peek function which display the priority elements of queue.
To display priority element, first check whether the queue is empty or not. If the condition is (rear == -
1) is true, an UNDERFLOW message is printed and exit.
If the queue is not empty, then traverse and display the elements of the priority queue:
for(i=front;i<=rear;i++){
printf("\n%d\n",Pqueue[i]);}
Implementation Of Priority Queue Using Linked List:
Operations On Priority queue:
1. Enqueue Operation
Before do any operations on priority queue, firstly, to define(create) a priority queue node structure.
struct node {
int data; //data is the data you want to store in queue
int priority;
struct node * next; // the *next will store location of next node if exists otherwise
NULL
};
Declare node type variables(front and rear),which front used to store the address of the first element of the
queue and rear used to store the address of the last element of the queue:
struct node *front, * rear ;
Create Penqueue function which the insertion of new element due to priority key on queue.
Declare the variable data which inserted new element on priority queue:
int data;
Create(declare) a new node variable(newNode) and allocate the space to new node :
struct node *newNode;
newNode = (struct node *) malloc (sizeof(struct node));
Check whether the newNode is empty or not. If the condition (newNode== NULL) is true, the newNode
node is empty then unable to insert the newNode node on queue then an APPROPRIATE message is
printed and exit.
If the newNode is not empty, store value into the data part of the new node and assign priority key to new
node:
newNode->data = data;// Assign data value to newly created node
newNode->priority = prior;
Check whether the queue is empty or not. If the condition (front == NULL && rear == NULL) is true, the
new element will be added on queue. To make the new node as the front and rear nodes:
front = newNode;
rear = newNode;
Make the next pointer of front and rear nodes will point to NULL:
front -> next = NULL;
rear -> next = NULL;
If the queue is contain more than one element, then to check a new node priority equal or smaller than front
node priority. If the condition (newNode->priority <= front->priority) is true, Create(declare) a
temporary(temp) node variable:
struct node *temp;
To make the temp node as front node:
temp = front;// Initialize the temp node to front node