You are on page 1of 60

Data Structure and Algorithm

Chapter Six
Stacks and Queues
Stacks
Introduction

• A simple data structure, in which insertion and deletion occur at


the same end, is termed (called) a stack. It is a LIFO (Last In First
Out) structure.

• The operations of insertion and deletion are called PUSH and


POP

Push - push (put) item onto stack

Pop - pop (get) item from stack


Cont.

Implementation:
Stacks can be implemented both as an array (contiguous list) and as
a linked list. We want a set of operations that will work with either
type of implementation: i.e. the method of implementation is hidden
and can be changed without affecting the programs that use them.
The basic Operations
Push()
{ Pop()
if there is room { {
put an item on the top of the stack if stack is not empty {
else return the value of the top item
give an error message remove the top item from the stack
} }
} else {
give an error message
}
}
CreateStack()
{
remove existing items from the stack
initialize the stack to empty
}
Array Implementation of Stacks
The PUSH Operation
• Here, addition of an element is known as the PUSH operation. So, if
an array is given to you, which is supposed to act as a STACK, you
know that it has to be a STATIC Stack; meaning, data will
overflow if you cross the upper limit of the array. So, keep this in
mind.
Algorithm:
• Step-1: Increment the Stack TOP by 1. Check whether it is always
less than the Upper Limit of the stack. If it is less than the Upper
Limit go to step-2 else report -"Stack Overflow“

• Step-2: Put the new element at the position pointed by the TOP
Cont.
Implementation:
• Note:- In array
int stack[UPPERLIMIT];
int top= -1; /*stack is empty*/ implementation, we have taken
..
TOP = -1 to signify the empty
main()
{ stack, as this simplifies the
..
implementation.
push(item);
..
}
push(int item)
{
top = top + 1;
if(top < UPPERLIMIT)
stack[top] = item; /*step-1 & 2*/
else
cout<<"Stack Overflow"; }
Array Implementation of Stacks
The POP Operation
• POP is the synonym for delete when it comes to Stack. So, if you're
taking an array as the stack, remember that you'll return an error
message, "Stack underflow", if an attempt is made to Pop an item
from an empty Stack.

Algorithm:
• Step-1: If the Stack is empty then give the alert "Stack underflow"
and quit; or else go to step-2
Step-2: a) Hold the value for the element pointed by the TOP
b) Put a NULL value instead
c) Decrement the TOP by 1
Implementation:
static int stack[UPPPERLIMIT];
int top=-1;
main() • Note: - Step-2:(b) signifies that
{
.. the respective element has
poped_val = pop(); been deleted.
..
}
int pop()
{
int del_val = 0;
if(top == -1)
cout<<"Stack underflow"; /*step-1*/
else
{
del_val = stack[top]; /*step-2*/
stack[top] = NULL;
top = top -1;
}
return(del_val); }
Exercise
1. Write the C++ full
void display()
implementation of static {
stack (using array). if (top==-1)
cout<<"\nstack is empity!! \n";
2. Compile and run your else{
int i;
code.
cout<<"\n Stack elements are: \n";
for(i=top; i>= 0; i--)
3. Use the following
cout<<stack[i];
function to display the }
}
stack elements.

Stack ARR FIM.cpp


Linked List Implementation of Stacks
The PUSH Operation
• It’s very similar to the insertion operation in a dynamic singly
linked list. The only difference is that here you'll add the new
element only at the end of the list, which means addition can
happen only from the TOP.

• Since a dynamic list is used for the stack, the Stack is also
dynamic, means it has no prior upper limit set. So, we don't have to
check for the Overflow condition at all!
Contd.

In Step [1] we create the new element to be pushed to the Stack.


In Step [2] the TOP most element is made to point to our newly
created element.
In Step [3] the TOP is moved and made to point to the last element in
the stack, which is our newly added element.
Contd.
Algorithm:

Step-1: If the Stack is empty go to step-2 or else go to step-3


Step-2: Create the new element and make your "stack" and "top"
pointers point to it and quit.
Step-3: Create the new element and make the last (top most) element
of the stack to point to it
Step-4: Make that new element your TOP most element by making
the "top" pointer point to it.
Implementation: push(int item)
{
if(stack == NULL) /*step-1*/
struct node{ {
int item; newnode = new node; /*step-2*/
newnode -> item = item;
struct node *next;
newnode -> next = NULL;
} stack = newnode;
struct node *stack = NULL; top = stack;
/*stack is initially empty*/
bottom=stack
struct node *top = stack;
}
struct node *bottom=stack; else
main() {
{ newnode = new node; /*step-3*/
.. newnode -> item = item;
.. newnode -> next = NULL;
push(item); top ->next = newnode;
.. top = newnode; /*step-4*/
} }
}
Linked List Implementation of Stacks
The POP Operation
• This is again very similar to the deletion operation in any Linked
List, but you can only delete from the end of the list and only one
at a time; and that makes it a stack.

• Here, we'll have a list pointer, "target", which will be pointing to


the last but one element in the List (stack).

• Every time we POP, the TOP most element will be deleted and
"target" will be made as the TOP most element.
Contd.

In step[1] we got the "target" pointing to the last but one node.
In step[2] we freed the TOP most element.
In step[3] we made the "target" node as our TOP most element.

Supposing you have only one element left in the Stack, then we won't
make use of "target" rather we'll take help of our "bottom" pointer.
Contd.
Algorithm:

Step-1: If the Stack is empty then give an alert message "Stack


Underflow" and quit; or else proceed
Step-2: If there is only one element left go to step-3 or else step-4
Step-3: Free that element and make the "stack", "top" and "bottom"
pointers point to NULL and quit
Step-4: Make "target" point to just one element before the TOP; free the
TOP most element; make "target" as your TOP most element
int pop( )
Implementation: {
int pop_val = 0;
struct node struct node *target = stack;
{ if(stack == NULL) /*step-1*/
int nodeval; cout<<"Stack Underflow";
struct node *next; else
{
} if(top == bottom) /*step-2*/
struct node *stack = NULL; {
/*stack is initially empty*/ pop_val = top -> nodeval; /*step-3*/
struct node *top = stack; delete top;
stack = NULL;
main() top = bottom = stack;
{ }
int newvalue, delval; else /*step-4*/
.. {
push(newvalue); while(target->next != top) target = target ->next;
pop_val = top->nodeval;
.. delete top;
delval = pop(); top = target;
/*POP returns the deleted target ->next = NULL; }
value from the stack*/ } }
return(pop_val); }
Exercise
void display(struct node *bottom)
1. Write the C++ full
{
implementation of Dynamic
if (bottom==NULL)
stack (using Linked List). cout<<"\nstack is empity!! \n";

else{
2. Compile and run your code.
display(bottom->next);
3. Use the following recursive cout<< bottom->item<<endl;

function to display your }

stack. }

Stack LL FIM.cpp
Application of Stacks

Evaluation of Algebraic Expressions


• An expression is a collection of operators and operands that
represents a specific value.

• In above definition, operator is a symbol which performs a


particular task like arithmetic operation or logical operation or
conditional operation etc.,

• Operands are the values on which the operators can perform the
task. Here operand can be a direct value or variable or address of
memory location. Based on the operator position, expressions are
divided into THREE types.
Contd.
• In infix expression, operator is used in between operands. The
general structure of an Infix expression is as follows...
Operand1 Operator Operand2 => (A+B)
• In postfix expression, operator is used after operands. We can say
that “Operator follows the Operands". The general structure of
Postfix expression is as follows...
Operand1 Operand2 Operator => AB+
• In prefix expression, operator is used before operands. We can
say that “Operands follows the Operator". The general structure of
prefix expression is as follows...
Operator Operand1 Operand2 => +AB

• Any expression can be represented using the above three different


types of expressions. And we can convert an expression from one
form to another form.
Infix to Postfix using Stack Data Structure
• The reason for using postfix notation is that a fairly simple algorithm
exists to evaluate such expressions based on a stack.

• consider postfix notation as a way of redistributing operators in an


expression so that their operation is delayed until the correct time.
Consider the following expression:
a+b*c+(d*e+f)*g
In postfix form the expression becomes:
abc*+de*f+g*+
Contd.
Algorithm
initialise stack and postfix output to empty;
while(not end of infix expression) {
get next infix item
if(item is value) append item to pfix o/p
else if(item == ‘(‘) push item onto stack
else if(item == ‘)’) {
pop stack to x
while(x != ‘(‘)
app.x to pfix o/p & pop stack to x
} else {
while(precedence(stack top) >= precedence(item))
pop stack to x & app.x to pfix o/p
push item onto stack }
}
while(stack not empty)
pop stack to x and append x to pfix o/p
Contd.

• Operator Precedence (for this algorithm):

4 : ‘(‘ - only popped if a matching ‘)’ is found

3 : All unary operators

2:/*

1:+-

• The algorithm immediately passes values (operands) to the postfix


expression, but remembers (saves) operators on the stack until
their right-hand operands are fully translated.
a+b*c+(d*e+f)*g
Evaluating Postfix Using Stacks
Algorithm
initialise stack to empty;
while (not end of postfix expression) {
get next postfix item;
if(item is value)
Binary operators:
push it onto the stack; +, -, *, /, etc.,
else if(item is binary operator) { Unary operators:
pop the stack to x; unary minus, square root,
pop the stack to y; sin, cos, exp, etc.,
perform y operator x;
push the results onto the stack; }
else if (item is unary operator) {
pop the stack to x;
perform operator(x);
push the results onto the stack }
}
The single value on the stack is the desired result.
Evaluating Postfix Using Stacks
• Infix Expression 6*(5+(2+3)*8+3)
• Consider the Postfix expression 6 5 2 3 + 8*+3+*
the first item is a value (6) so it is pushed onto the stack
the next item is a value (5) so it is pushed onto the stack
the next item is a value (2) so it is pushed onto the stack
the next item is a value (3) so it is pushed onto the stack
and the stack becomes
1
Contd.
• Consider the Postfix expression 6 5 2 3 + 8*+3+* 2
the remaining items are now: + 8 * + 3 + *
So next a '+' is read (a binary operator),
so 3 and 2 are popped from the stack and
their sum '5' is pushed onto the stack:

Next 8 is pushed and the next 3


item is the operator *:
Contd.
6 5 2 3 + 8*+3+*
4

Next the operator + followed by 3:

Next is operator +, so 3 and 45


Next is operator *, so 48 and 6 are
are popped and 45+3=48 is
popped, and 6*48=288 is pushed
pushed
5 6
Application of Stacks

Function Calls
• Reading Assignment!
Queues
Introduction

• Queue data structure is a collection of similar data items in which


insertion and deletion operations are performed based on FIFO
(First In First Out) principle.

• Queue is a linear data structure in which the insertion and


deletion operations are performed at two different ends.

• The insertion operation is performed at a position which is


known as 'rear' and the deletion operation is performed at a
position which is known as 'front‘.
Operations on a Queue
• The following operations are performed on a queue data
structure...
1. enQueue(value) - To insert an element into the queue
2. deQueue() - To delete an element from the queue
3. display() - To display the elements of the queue
Contd.

• Example

Operation Content of queue


Enqueue(B) B
Enqueue(C) B, C
Dequeue() C
Enqueue(G) C, G
Enqueue (F) C, G, F
Dequeue() G, F
Enqueue(A) G, F, A
Dequeue() F, A
Implementation of a Queue

• Queue data structure can be implemented in two ways. They are as


follows...

1. Using Array

2. Using Linked List

• When a queue is implemented using array, that queue can


organize only limited number of elements.

• When a queue is implemented using linked list, that queue can


organize unlimited number of elements.
Simple Array implementation of enqueue and
dequeue operations
• Queue implemented using array can store only fixed number of data
values.

• The implementation of queue data structure using array is very simple,


just define a one dimensional array of specific size and insert or delete
the values into that array by using FIFO principle with the help of
variables 'front' and 'rear'. Initially both 'front' and 'rear' are set to -1.

• Whenever, we want to insert a new value into the queue, increment


'rear' value by one and then insert at that position.

• Whenever we want to delete a value from the queue, then increment


'front' value by one and then display the value at 'front' position as
deleted element.
Contd.

enQueue(value) – Steps to insert a value into the queue

• The enQueue() function takes one value as parameter and inserts that value
into the queue. An integer variable (QUEUESIZE) that tells the total number
of data in the queue is used.

• Step 1: Check whether queue is FULL. (rear == SIZE-1)

• Step 2: If it is FULL, then display "Queue Overflow" and terminate the


function.

• Step 3: If it is NOT FULL, then increment rear value by one (rear++) and
set queue[rear] = value.

• Step 4: Increment QUEUESIZE value by one (QUEUESIZE ++)

• Step 5: If front == -1 , then increment front value by one (front ++)


Contd.

enQueue(value) – Implementation
const int SIZE=100;
int FRONT =-1, REAR =-1;
int QUEUESIZE = 0;
Int Num[SIZE];
void enQueue(int x)
{
if(Rear<SIZE-1)
{
REAR++;
Num[REAR]=x;
QUEUESIZE++;
if(FRONT = = -1)
FRONT++;
}
else
cout<<"Queue Overflow";
}
Contd.

deQueue( ) – Steps to delete a value from the queue

• The deQueue() function does not take any value as parameter


since the element is always deleted from front position.
• Step 1: Check whether queue is EMPTY. (rear == front or
QUEUESIZE== 0)

• Step 2: If it is EMPTY, then display "Queue Underflow" and


terminate the function.

• Step 3: If it is NOT EMTY, then increment front value by one


(front++) and display queue[front] as deleted element.

• Step 4: Decrement QUEUESIZE value by one (QUEUESIZE --)


Contd.

deQueue(value) – Implementation

int deQueue( )
{
int x;
if(QUEUESIZE>0)
{
x=Num[FRONT];
FRONT++;
QUEUESIZE--;

}
else
cout<<"Queue Underflow";
return(x);
}
Contd.

display( ) – Steps to display elements of a queue

• Step 1: Check whether queue is EMPTY. (rear == front or


QUEUESIZE== 0)

• Step 2: If it is EMPTY, then display "Queue Empty" and terminate


the function.

• Step 3: If it is NOT EMTY, then define an integer variable 'i' and set
'i = front'.

• Step 4: Display 'queue[i]' value and increment 'i' value by one (i++).
Repeat the same until 'i' value is equal to rear (i <= rear)
Contd.

display() – Implementation

void display()
{
if(QUEUESIZE==0)
cout<<“\nQueue is Empty";

else
{
cout<<“\n Queue elements are ";
for(i = front; i<= rear ; i++)
cout<<“\t”<< Num[i];
}
}
EX
Combine the above simple array implementations into a single
C++ program and Run it.

Queue SAFIM2.cpp
Linked List implementation of enqueue and
dequeue operations
• Queue using array is not suitable when we don't know the size of
data which we are going to use.

• A queue which is implemented using linked list can work for unlimited
number of values. That means, queue using linked list can work for
variable size of data (No need to fix the size at beginning of the
implementation).

• In linked list implementation of a queue, the last inserted node is always


pointed by 'rear' and the first node is always pointed by 'front'.

• Example
Contd.

enQueue(value) – Steps to insert an element into the queue

• We can use the following steps to insert a new node into the queue...

• Step 1: Create a newNode with given value and set 'newNode → next'
to NULL.

• Step 2: Check whether queue is Empty (rear == NULL)

• Step 3: If it is Empty then, set front = newNode and rear = newNode.

• Step 4: If it is Not Empty then, set rear →


next = newNode and rear = newNode.
Contd.

enQueue(value) – Implementation

void enQueue(int value)


{
struct Node *newNode;
newNode = new Node;
newNode->data = value;
newNode -> next = NULL;
if(front == NULL)
front = rear = newNode;
else{
rear -> next = newNode;
rear = newNode;
}
cout<<"\nInsertion is Success!!!\n";
}
Contd.

deQueue( ) – Steps to delete a value from the queue

• We can use the following steps to delete a node from the queue...

• Step 1: Check whether queue is Empty (front == NULL).

• Step 2: If it is Empty, then display "Queue is Empty!!! Deletion is


not possible!!!" and terminate from the function

• Step 3: If it is Not Empty then, define a Node pointer 'temp' and set it
to 'front'.

• Step 4: Then set 'front = front → next' and delete 'temp' .


Contd.

deQueue(value) – Implementation

void deQueue()
{
if(front == NULL)
cout<<"\nQueue is Empty!!!\n";
else{
struct Node *temp = front;
front = front -> next;
cout<<"\nDeleted element: %d\n", temp->data;
delete temp;
}
}
Contd.

display( ) – Steps to display elements of a queue


• We can use the following steps to display the elements (nodes) of a
queue...

• Step 1: Check whether queue is Empty (front == NULL).

• Step 2: If it is Empty then, display 'Queue is Empty!!!' and terminate


the function.

• Step 3: If it is Not Empty then, define a Node pointer 'temp' and


initialize with front.

• Step 4: Display 'temp → data --->' and move it to the next node.
Repeat the same until 'temp' reaches to 'rear' (temp → next !=NULL
or temp !=NULL).
Contd.

display() – Implementation
void display()
{
if(front == NULL)
cout<<"\nQueue is Empty!!!\n";
else{
struct Node *temp = front;
while(temp != NULL){
cout<<temp->data<<"--->";
temp = temp -> next;
}
cout<<"NULL";
}}
EX
Combine the above Linked List implementations into a single C++
program and Run it.

Queue LLFIM.cpp
Deque (pronounced as Deck)
• Deque is a Double Ended Queue
• Insertion and deletion can occur at either end
• Deque has the following basic operations
EnqueueFront – inserts data at the front of the list
DequeueFront – deletes data at the front of the list
EnqueueRear – inserts data at the end of the list
DequeueRear – deletes data at the end of the list
• Implementation is similar to that of queue.
• Deque is best implemented using doubly linked list
Priority Queue

• Priority Queue is a queue where each data has an associated key that is
provided at the time of insertion.

• Dequeue operation deletes data having highest priority in the list

• One of the previously used dequeue or enqueue operations has to be


modified

Example: Consider the following queue of persons where females have


higher priority than males (gender is the key to give priority).
Demerging Queues
• It is the process of creating two or more queues from a single queue.
• used to give priority for some groups of data.
• Example: The following two queues can be created from the above
priority queue

Algorithm:
create empty females and males queue
while (PriorityQueue is not empty)
{
Data=DequeuePriorityQueue(); // delete data at the front
if(gender of Data is Female)
EnqueueFemale(Data);
else
EnqueueMale(Data);
}
EX.

Write a C++ implementation of the above algorithm


(Demerging Queues)
Merging Queues
Contd.
Algorithm:
EX.

Write a C++ implementation of the above algorithm (Merging


Queues)
Application of Queues

You might also like