MODULE-II
MODULE-II
MODULE-II
Stacks and Queues
Stacks: Definition, Stack Operations, Array Representation of Stacks, Stacks using Dynamic Arrays, Stack Applications: Polish
notation, Infix to postfix conversion, valuation of postfix expression, Recursion - Factorial, GCD, Fibonacci Sequence, Tower of
Hanoi, Ackerman's function. Queues: Definition, Array Representation, Queue Operations, Circular Queues, Circular queues using
Dynamic arrays, Dequeues, Priority Queues, A Mazing Problem. Multiple Stacks and Queues. Programming Examples.
Stacks:
Definition
A stack is an ordered collection of items into which new items may be inserted and from which items may be deleted at one end,
called the top of the stack. Hence, a stack is called a LIFO (Last-In-First-Out) data structure, as the element that was inserted last is the
first one to be taken out.
Stack Operations
A stack supports two basic operations: push and pop. The push operation adds an element to the top of the stack and the pop operation
removes the element from the top of the stack.
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.
However, before inserting the value, we must first check if TOP=MAX–1, if the stack is full and no more insertions can be done. If an
attempt is made to insert a value in a stack that is already full, an OVERFLOW message is printed.
Example:
To insert an element with value 6, we first check if TOP=MAX–1. If the condition is false, then we increment the value of
TOP and store the new element at the position given by stack [TOP]. The figure shows the updated stack.
Algorithm:
Step: 1 We first check for the OVERFLOW condition.
Step: 2 TOP is incremented so that it points to the next location in the array.
Step: 3 The value is stored in the stack at the location pointed by TOP.
S.TAMILARASAN Page 1
DATA STRUCTURES AND APPLICATIONS
Pop Operation
The pop operation is used to delete the topmost element from the stack. However, before deleting the value, we must first check if
TOP=NULL because if that is the case, then it means the stack is empty and no more deletions can be done. If an attempt is made to
delete a value from a stack that is already empty, an UNDERFLOW message is printed.
Example:
Consider the stack given
To delete the topmost element, we first check if TOP=NULL. If the condition is false, then we decrement the value pointed by TOP.
Algorithm:
Step: 1 We first check for the UNDERFLOW condition.
Step: 2 The value of the location in the stack pointed by TOP is stored in VAL.
Step: 3 TOP is decremented.
S.TAMILARASAN Page 2
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 3
DATA STRUCTURES AND APPLICATIONS
return 0;
}
void push(int st[], int val)
{
if(top == MAX-1)
{
printf("\n STACK OVERFLOW");
}
else
{
top++;
st[top] = val;
}
}
int pop(int st[])
{
int val;
if(top == -1)
{
printf("\n STACK UNDERFLOW");
return -1;
}
else
{
val = st[top];
top--;
return val;
}
}
void display(int st[])
{
int i;
if(top == -1)
printf("\n STACK IS EMPTY");
else
{
for(i=top;i>=0;i--)
printf("\n %d",st[i]);
S.TAMILARASAN Page 4
DATA STRUCTURES AND APPLICATIONS
To insert an element with value 9, we first check if TOP=NULL, then we allocate memory for a new node; store the value in its
DATA part and NULL in its NEXT part. The new node will then be called TOP. However, if TOP! =NULL, then we insert the new
node at the beginning of the linked stack and name this new node as TOP.
Algorithm
Step: 1 Memory is allocated for the new node.
Step: 2 The DATA part of the new node is initialized with the value to be stored in the node.
Step: 3 We check if the new node is the first node of the linked list. This s done by checking if TOP = NULL.
In case the IF statement evaluates to true, then NULL is stored in the NEXT part of the node and the new node is called TOP.
However, if the new node is not the first node in the list, then it is added before the first node of the list (that is, the TOP node) and
termed as TOP.
Pop Operation
The pop operation is used to delete the topmost element from a stack. However, before deleting the value, we must first check if
TOP=NULL, because if this is the case, then it means that the stack is empty and no more deletions can be done. If an attempt is made
to delete a value from a stack that is already empty, an UNDERFLOW message is printed.
S.TAMILARASAN Page 5
DATA STRUCTURES AND APPLICATIONS
In case TOP! =NULL, then we will delete the node pointed by TOP, and make TOP point to the second element of the linked stack.
Algorithm
Step: 1 We first check for the UNDERFLOW condition.
Step: 2 We use a pointer PTR that points to TOP.
Step: 3 TOP is made to point to the next node in sequence.
Step: 4 The memory occupied by PTR is given back to the free pool.
Program for stack implementation using dynamic array
/* dynamic stack */
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *top = NULL;
void display();
void push(int);
void pop();
int main()
{
int n, ch;
do
{
printf("\n\nStack Menu\n1. Push \n2. Pop\n3. Display\n0. Exit");
printf("\nEnter Choice 0-3? : ");
scanf("%d", &ch);
switch (ch)
{
case 1:
printf("\nEnter number ");
scanf("%d", &n);
push(n);
break;
case 2:
S.TAMILARASAN Page 6
DATA STRUCTURES AND APPLICATIONS
pop();
break;
case 3:
display();
break;
}
}while (ch != 0);
}
void push(int item)
{
struct node *nptr = malloc(sizeof(struct node));
nptr->data = item;
nptr->next = top;
top = nptr;
}
void display()
{
struct node *temp;
temp = top;
while (temp != NULL)
{
printf("\n%d", temp->data);
temp = temp->next;
}
}
void pop()
{
if (top == NULL)
{
printf("\n\nStack is empty ");
}
else
{
struct node *temp;
temp = top;
top = top->next;
printf("\n\n%d deleted", temp->data);
free(temp);
S.TAMILARASAN Page 7
DATA STRUCTURES AND APPLICATIONS
}
}
Stack Applications
Polish notation
There are three different polish notations are infix notation, postfix notation and prefix notation.
Infix notation (Operand1, Operator, Operand2): The operator is placed in between the operands. For example, A+B; here, plus
operator are placed between the two operands A and B.
Postfix notation (Operand1, Operand2, Operator): the operator is placed after the operands. For example, if an expression is written
as A+B in infix notation, the same expression can be written as AB+ in postfix notation. The order of evaluation of a postfix
expression is always from left to right. Even brackets cannot alter the order of evaluation.
S.TAMILARASAN Page 8
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 9
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 10
DATA STRUCTURES AND APPLICATIONS
char *e, x;
printf("Enter the expression :: ");
scanf("%s",exp);
e = exp;
while(*e != '\0')
{
if(isalnum(*e))
printf("%c",*e);
else if(*e == '(')
push(*e);
else if(*e == ')')
{
while((x = pop()) != '(')
printf("%c", x);
}
else
{
while(priority(stack[top]) >= priority(*e))
printf("%c",pop());
push(*e);
}
e++;
}
while(top != -1)
{
printf("%c",pop());
}
}
A+ (B*C-(D/E-F)*G)*H
Infix Expression Stack Postfix Expression(output) Comments
5^E+D*(C^B+A) Empty Initial
^E+D*(C^B+A) Empty 5 Print
E+D*(C^B+A) ^ 5 Push ^
+D*(C^B+A) ^ 5E Print
+D*(C^B+A) Empty 5E^ Pop ^
D*(C^B+A) + 5E^ Push +
*(C^B+A) + 5E^D Print
S.TAMILARASAN Page 11
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 12
DATA STRUCTURES AND APPLICATIONS
main()
{
char exp[20];
char *e, x;
printf("Enter the expression :: ");
scanf("%s",exp);
e = exp;
while(*e != '\0')
{
if(isalnum(*e))
printf("%c",*e);
else if(*e == '(')
push(*e);
else if(*e == ')')
{
while((x = pop()) != '(')
printf("%c", x);
}
else
{
while(priority(stack[top]) >= priority(*e))
printf("%c",pop());
push(*e);
}
e++;
}
while(top != -1)
{
printf("%c",pop());
}
}
S.TAMILARASAN Page 13
DATA STRUCTURES AND APPLICATIONS
Let us now take an example that makes use of this algorithm. Consider the infix expression given as 9 – ((3 * 4) + 8) / 4. Evaluate the
expression. The infix expression 9 – ((3 * 4) + 8) / 4 can be written as 9 3 4 * 8 + 4 / – using postfix notation.
Postfix Expression Stack
934*8+4/- 9
4*8+4/- 93
*8+4/- 934
8+4/- 9 12
+4/- 9 12 8
4/- 9 20
/- 9 20 4
- 95
End 4
Algorithm
S.TAMILARASAN Page 14
DATA STRUCTURES AND APPLICATIONS
}
void main()
case '+': return op1 + op2;
case' -': return op1 - op2;
case '*': return op1 * op2;
case '/': return op1 / op2;
case '$':
case '^': return pow(op1,op2);
default: return 0;
{
double s[20], res, op1, op2;
int top, i;
char postfix[20], symbol;
clrscr();
printf("\nEnter the postfix expression:\n");
flushall();
gets(postfix);
top=-1;
for(i=0; <strlen(postfix); i++)
{
symbol = postfix[i];
if(isdigit(symbol))
s[++top] = symbol - '0';
else
{
op2 = s[top--];
op1 = s[top--];
res = compute(symbol, op1, op2);
s[++top] = res;
}
}
res = s[top--];
printf("\nThe result is : %f\n", res);
getch();
}
Recursion
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 which does
not require a call to itself.
Factorial
To calculate n!, we multiply the number with factorial of the number that is 1 less than that number. In other words, n! = n ¥ (n–1)!
Let us say we need to find the value of 5!
5! = 5 * 4 * 3 * 2 * 1
= 120
This can be written as
S.TAMILARASAN Page 15
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 16
DATA STRUCTURES AND APPLICATIONS
From the above example, let us analyses the steps of a recursive program.
Step: 1 Specify the base case which will stop the function from making a call to itself.
Step: 2 Check to see whether the current value being processed matches with the value of the base case. If yes, process and return
the value.
Step: 3 Divide the problem into smaller or simpler sub-problems.
Step: 4 Call the function from each sub-problem.
Step: 5 Combine the results of the sub-problems.
Step: 6 Return the result of the entire problem.
Greatest Common Divisor
The greatest common divisor of two numbers (integers) is the largest integer that divides both the numbers. We can find the GCD of
two numbers recursively by using the Euclid’s algorithm that states
GCD can be implemented as a recursive function because if b does not divide a, then we call the same function (GCD) with another
set of parameters that are smaller than the original ones. Here we assume that a > b. However if a < b, then interchange a and b in the
formula given above.
Working
1. Assume a = 62 and b = 8
2. GCD(62, 8)
3. rem = 62 % 8 = 6
4. GCD(8, 6)
5. rem = 8 % 6 = 2
6. GCD(6, 2)
7. rem = 6 % 2 = 0
8. Return 2
9. Return 2
10. Return 2
Program for GCD
#include <stdio.h>
int GCD(int, int);
int main()
{
int num1, num2, res;
printf("\n Enter the two numbers: ");
scanf("%d %d", &num1, &num2);
res = GCD(num1, num2);
printf("\n GCD of %d and %d = %d", num1, num2, res);
S.TAMILARASAN Page 17
DATA STRUCTURES AND APPLICATIONS
return 0;
}
int GCD(int x, int y)
{
int rem;
rem = x%y;
if(rem==0)
return y;
else
return (GCD(y, rem));
}
Fibonacci sequence
The Fibonacci series can be given as
0 1 1 2 3 5 8 13 21 34 55 ……
That is, the third term of the series is the sum of the first and second terms. Similarly, fourth term is the sum of second and third terms,
and so on. Now we will design a recursive solution to find the nth term of the Fibonacci series. The general formula to do so can be
given as
As per the formula, FIB (0) =0 and FIB (1) = 1. So we have two base cases. This is necessary because every problem is divided into
two smaller problems.
Program for Fibonacci
#include <stdio.h>
int Fibonacci(int);
int main()
{
int n, i = 0, res;
printf("Enter the number of terms\n");
scanf("%d",&n);
printf("Fibonacci series\n");
for(i = 0; i < n; i++ )
{
res = Fibonacci(i);
printf("%d\t",res);
}
return 0;
S.TAMILARASAN Page 18
DATA STRUCTURES AND APPLICATIONS
}
int Fibonacci(int n)
{
if ( n == 0 )
return 0;
else if ( n == 1 )
return 1;
else
return ( Fibonacci(n–1) + Fibonacci(n–2) );
}
Tower of Hanoi
The Tower of Hanoi is a mathematical game or puzzle. It consists of three rods, and a number of disks of different sizes which can
slide onto any rod. The puzzle starts with the disks in a neat stack in ascending order of size on one rod, the smallest at the top, thus
making a conical shape. The objective of the puzzle is to move the entire stack to another rod, obeying the following simple rules:
Only one disk can be moved at a time.
Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack i.e. a disk can only
be moved if it is the uppermost disk on a stack.
No disk may be placed on top of a smaller disk.
With three disks, the puzzle can be solved in seven moves. The minimum number of moves required to solve a Tower of Hanoi puzzle
is 2n - 1, where n is the number of disks.
Program for Tower of Hanoi
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
main ()
{
int n;
clrscr();
printf("\n Enter the number of rings: ");
scanf("%d", &n);
move(n,'A', 'C', 'B');
getch();
return 0;
}
void move(int n, char source, char dest, char spare)
{
if (n==1)
printf("\n Move disk %d from %c to %c", n, source, dest);
else
S.TAMILARASAN Page 19
DATA STRUCTURES AND APPLICATIONS
{
move(n–1,source,spare,dest);
printf("\n Move disk %d from %c to %c", n, source, dest);
move(n–1,spare,dest,source);
}
}
S.TAMILARASAN Page 20
DATA STRUCTURES AND APPLICATIONS
Ackerman's function.
In computability theory, the Ackermann function, named after Wilhelm Ackermann, is one of the simplest and earliest-discovered
examples of a total computable function that is not primitive recursive. All primitive recursive functions are total and computable, but
the Ackermann function illustrates that not all total computable functions are primitive recursive. The Ackermann function is
defined for integer and by
Computing the Ackermann function can be restated in terms of an infinite table. We place the natural numbers along the top row. To
determine a number in the table, take the number immediately to the left, and then look up the required number in the previous row, at
the position given by the number just taken. If there is no number to its left, simply look at the column headed "1" in the previous row.
Here is a small upper-left portion of the table:
The numbers listed here in a recursive reference are very large and cannot be easily notated in some other form. Despite the large
values occurring in this early section of the table, some even larger numbers have been defined, such as Graham's number, which
cannot be written with any small number of Knuth arrows. This number is constructed with a technique similar to applying the
Ackermann function to itself recursively. This is a repeat of the above table, but with the values replaced by the relevant expression
from the function definition to show the pattern clearly:
S.TAMILARASAN Page 21
DATA STRUCTURES AND APPLICATIONS
Expansion
To see how the Ackermann function grows so quickly, it helps to expand out some simple expressions using the rules in the original
definition. For example, we can fully evaluate in the following way:
Program
C program to illustrate Ackermann’s Function
#include<stdio.h>
static int w=0;
int ackerman(int m,int n)
{
w=w+1;
if(m==0)
return n+1;
else if(m>0 && n==0)
return ackerman(m-1,1);
S.TAMILARASAN Page 22
DATA STRUCTURES AND APPLICATIONS
Array Representation
S.TAMILARASAN Page 23
DATA STRUCTURES AND APPLICATIONS
In the following example figure, front = 0 and rear = 5 suppose we want to add another element with value 45, then rear would be
incremented by 1 and the value would be stored at the position pointed by rear.
Here, front = 0 and rear = 6. Every time a new element has to be added, we repeat the same procedure. If we want to delete an element
from the queue, then the value of front will be incremented. Deletions are done from only this end of the queue.
Queue operation
Insertion
However, before inserting an element in a queue, we must check for overflow conditions. An overflow will occur when we try to
insert an element into a queue that is already full. When rear =MAX– 1, where MAX is the size of the queue, we have an overflow
condition. Note that we have written MAX – 1 because the index starts from 0.
1. We first check for the overflow condition.
2. We check if the queue is empty. In case the queue is empty, then both front and rear are set to zero, so that the new
value can be stored at the 0 location. Otherwise, if the queue already has some values, then rear is incremented so
that it points to the next location in the array.
3. The value is stored in the queue at the location pointed by rear.
S.TAMILARASAN Page 24
DATA STRUCTURES AND APPLICATIONS
Deletion
Before deleting an element from a queue, we must check for underflow conditions. An underflow condition occurs when we try to
delete an element from a queue that is already empty. If front = –1 and rear = –1, it means there is no element in the queue.
void enQueue(int);
void deQueue();
void display();
void main()
{
int value, choice;
clrscr();
while(1){
printf("\n\n***** MENU *****\n");
printf("1. Insertion\n2. Deletion\n3. Display\n4. Exit");
printf("\nEnter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("Enter the value to be insert: ");
scanf("%d",&value);
enQueue(value);
break;
case 2: deQueue();
break;
case 3: display();
S.TAMILARASAN Page 25
DATA STRUCTURES AND APPLICATIONS
break;
case 4: exit(0);
default: printf("\nWrong selection!!! Try again!!!");
}
}
}
void enQueue(int value){
if(rear == SIZE-1)
printf("\nQueue is Full!!! Insertion is not possible!!!");
else{
if(front == -1)
front = 0;
rear++;
queue[rear] = value;
printf("\nInsertion success!!!");
}
}
void deQueue(){
if(front == rear)
printf("\nQueue is Empty!!! Deletion is not possible!!!");
else{
printf("\nDeleted : %d", queue[front]);
front++;
if(front == rear)
front = rear = -1;
}
}
void display(){
if(rear == -1)
printf("\nQueue is Empty!!!");
else{
int i;
printf("\nQueue elements are:\n");
for(i=front; i<=rear; i++)
printf("%d\t",queue[i]);
}
}
S.TAMILARASAN Page 26
DATA STRUCTURES AND APPLICATIONS
Circular Queues
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. It is also called ‘Ring Buffer’.
In a normal Queue, we can insert elements until queue becomes full. But once queue becomes full, we cannot insert the next element
even if there is a space in front of queue.
S.TAMILARASAN Page 27
DATA STRUCTURES AND APPLICATIONS
/*
* C Program to Implement Queue Data Structure using Linked List
*/
#include <stdio.h>
#include <stdlib.h>
struct node
{
int info;
struct node *ptr;
}*front,*rear,*temp,*front1;
int frontelement();
void enq(int data);
void deq();
void empty();
void display();
void create();
void queuesize();
int count = 0;
void main()
{
int no, ch, e;
printf("\n 1 - Enque");
printf("\n 2 - Deque");
printf("\n 3 - Front element");
printf("\n 4 - Empty");
printf("\n 5 - Exit");
printf("\n 6 - Display");
printf("\n 7 - Queue size");
create();
while (1)
{
printf("\n Enter choice : ");
scanf("%d", &ch);
switch (ch)
{
case 1:
printf("Enter data : ");
scanf("%d", &no);
S.TAMILARASAN Page 28
DATA STRUCTURES AND APPLICATIONS
enq(no);
break;
case 2:
deq();
break;
case 3:
e = frontelement();
if (e != 0)
printf("Front element : %d", e);
else
printf("\n No front element in Queue as queue is empty");
break;
case 4:
empty();
break;
case 5:
exit(0);
case 6:
display();
break;
case 7:
queuesize();
break;
default:
printf("Wrong choice, Please enter correct choice ");
break;
}
}
}
/* Create an empty queue */
void create()
{
front = rear = NULL;
}
/* Returns queue size */
void queuesize()
{
printf("\n Queue size : %d", count);
S.TAMILARASAN Page 29
DATA STRUCTURES AND APPLICATIONS
}
/* Enqueing the queue */
void enq(int data)
{
if (rear == NULL)
{
rear = (struct node *)malloc(1*sizeof(struct node));
rear->ptr = NULL;
rear->info = data;
front = rear;
}
else
{
temp=(struct node *)malloc(1*sizeof(struct node));
rear->ptr = temp;
temp->info = data;
temp->ptr = NULL;
rear = temp;
}
count++;
}
/* Displaying the queue elements */
void display()
{
front1 = front;
if ((front1 == NULL) && (rear == NULL))
{
printf("Queue is empty");
return;
}
while (front1 != rear)
{
printf("%d ", front1->info);
front1 = front1->ptr;
}
if (front1 == rear)
printf("%d", front1->info);
}
S.TAMILARASAN Page 30
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 31
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 32
DATA STRUCTURES AND APPLICATIONS
int queue[SIZE];
int rear = 0, front = 0;
int main()
{
char ch;
int choice1, choice2, value;
printf("\n******* Type of Double Ended Queue *******\n");
do
{
printf("\n1.Input-restricted deque \n");
printf("2.output-restricted deque \n");
printf("\nEnter your choice of Queue Type : ");
scanf("%d",&choice1);
switch(choice1)
{
case 1:
printf("\nSelect the Operation\n");
printf("1.Insert\n2.Delete from Rear\n3.Delete from Front\n4. Display");
do
{
printf("\nEnter your choice for the operation in c deque: ");
scanf("%d",&choice2);
switch(choice2)
{
case 1: enQueueRear(value);
display();
break;
case 2: value = deQueueRear();
printf("\nThe value deleted is %d",value);
display();
break;
case 3: value=deQueueFront();
printf("\nThe value deleted is %d",value);
display();
break;
case 4: display();
break;
default:printf("Wrong choice");
S.TAMILARASAN Page 33
DATA STRUCTURES AND APPLICATIONS
}
printf("\nDo you want to perform another operation (Y/N): ");
ch=getch();
}while(ch=='y'||ch=='Y');
getch();
break;
case 2 :
printf("\n---- Select the Operation ----\n");
printf("1. Insert at Rear\n2. Insert at Front\n3. Delete\n4. Display");
do
{
printf("\nEnter your choice for the operation: ");
scanf("%d",&choice2);
switch(choice2)
{
case 1: enQueueRear(value);
display();
break;
case 2: enQueueFront(value);
display();
break;
case 3: value = deQueueFront();
printf("\nThe value deleted is %d",value);
display();
break;
case 4: display();
break;
default:printf("Wrong choice");
}
printf("\nDo you want to perform another operation (Y/N): ");
ch=getch();
} while(ch=='y'||ch=='Y');
getch();
break ;
}
printf("\nDo you want to continue(y/n):");
ch=getch();
}while(ch=='y'||ch=='Y');
S.TAMILARASAN Page 34
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 35
DATA STRUCTURES AND APPLICATIONS
}
int deQueueRear()
{
int deleted;
if(front == rear)
{
printf("\nQueue is Empty!!! Deletion is not possible!!!");
return 0;
}
front--;
deleted = queue[front+1];
return deleted;
}
int deQueueFront()
{
int deleted;
if(front == rear)
{
printf("\nQueue is Empty!!! Deletion is not possible!!!");
return 0;
}
rear++;
deleted = queue[rear-1];
return deleted;
}
void display()
{
int i;
if(front == rear)
printf("\nQueue is Empty!!! Deletion is not possible!!!")
else{
printf("\nThe Queue elements are:");
for(i=rear; i < front; i++)
{
printf("%d\t ",queue[i]);
}
}
}
S.TAMILARASAN Page 36
DATA STRUCTURES AND APPLICATIONS
Priority Queues
Priority Queue is an extension of queue with following properties.
1. Every item has a priority associated with it.
2. An element with high priority is dequeued before an element with low priority
3. If two elements have the same priority, they are served according to their order in the queue.
Program for priority queue implementation
/*
* C Program to Implement Priority Queue to Add and Delete Elements
*/
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
void insert_by_priority(int);
void delete_by_priority(int);
void create();
void check(int);
void display_pqueue();
int pri_que[MAX];
int front, rear;
void main()
{
int n, ch;
printf("\n1 - Insert an element into queue");
printf("\n2 - Delete an element from queue");
printf("\n3 - Display queue elements");
printf("\n4 - Exit");
create();
while (1)
{
printf("\nEnter your choice : ");
scanf("%d", &ch);
switch (ch)
{
case 1:
printf("\nEnter value to be inserted : ");
scanf("%d",&n);
insert_by_priority(n);
break;
S.TAMILARASAN Page 37
DATA STRUCTURES AND APPLICATIONS
case 2:
printf("\nEnter value to delete : ");
scanf("%d",&n);
delete_by_priority(n);
break;
case 3:
display_pqueue();
break;
case 4:
exit(0);
default:
printf("\nChoice is incorrect, Enter a correct choice");
}
}
}
/* Function to create an empty priority queue */
void create()
{
front = rear = -1;
}
/* Function to insert value into priority queue */
void insert_by_priority(int data)
{
if (rear >= MAX - 1)
{
printf("\nQueue overflow no more elements can be inserted");
return;
}
if ((front == -1) && (rear == -1))
{
front++;
rear++;
pri_que[rear] = data;
return;
}
else
check(data);
rear++;
S.TAMILARASAN Page 38
DATA STRUCTURES AND APPLICATIONS
}
/* Function to check priority and place element */
void check(int data)
{
int i,j;
for (i = 0; i <= rear; i++)
{
if (data >= pri_que[i])
{
for (j = rear + 1; j > i; j--)
{
pri_que[j] = pri_que[j - 1];
}
pri_que[i] = data;
return;
}
}
pri_que[i] = data;
}
S.TAMILARASAN Page 39
DATA STRUCTURES AND APPLICATIONS
pri_que[i] = -99;
rear--;
if (rear == -1)
front = -1;
return;
}
}
printf("\n%d not found in queue to delete", data);
}
/* Function to display queue elements */
void display_pqueue()
{
if ((front == -1) && (rear == -1))
{
printf("\nQueue is empty");
return;
}
for (; front <= rear; front++)
{
printf(" %d ", pri_que[front]);
}
front = 0;
}
Multi stack
When a stack is created using single array, we cannot able to store large amount of data, thus this problem is rectified using more than
one stack in the same array of sufficient array. This technique is called as Multiple Stack.
Note:
When an array of STACK[n] is used to represent two stacks, say Stack A and Stack B. Then the value of n is such that the combined
size of both the Stack[A] and Stack[B] will never exceed n. Stack[A] will grow from left to right, whereas Stack[B] will grow in
opposite direction i.e.) right to left.
S.TAMILARASAN Page 40
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 41
DATA STRUCTURES AND APPLICATIONS
printf("\t %d",stack[i]);
}
}
void pushB(int val)
{
if(topB-1 == topA)
printf("\n Overflow");
else
{
topB-=1;
stack[topB] = val;
}
}
int popB()
{
int val;
if(topB == MAX)
{
printf("\n Underflow");
val = -999;
}
else
{
val = stack[topB];
topB++;
}
}
void display_stackB()
{
int i;
if(topB == MAX)
printf("\n Stack B is Empty");
else
{
for(i = topB; i < MAX;i++)
printf("\t %d",stack[i]);
}
}
S.TAMILARASAN Page 42
DATA STRUCTURES AND APPLICATIONS
int main()
{
int option, val;
do
{
printf("\n -----Menu----- ");
printf("\n 1. PUSH a element into Stack A");
printf("\n 2. PUSH a element into Stack B");
printf("\n 3. POP a element from Stack A");
printf("\n 4. POP a element from Stack B");
printf("\n 5. Display the Stack A");
printf("\n 6. Display the Stack B");
printf("\n 7. Exit");
printf("\n Enter your choice");
scanf("%d",&option);
switch(option)
{
case 1:
printf("\n Enter the value to push on stack A :");
scanf("%d",&val);
pushA(val);
break;
case 2:
printf("\n Enter the value to push on stack B:");
scanf("%d", &val);
pushB(val);
break;
case 3:
if(val != -999)
printf("\n The value popped from Stack A = %d", val);
break;
case 4:
if(val != -999)
printf("\n The value popped from Stack B = %d",val);
break;
case 5:
printf("\n The contents of Stack A are :\n");
display_stackA();
S.TAMILARASAN Page 43
DATA STRUCTURES AND APPLICATIONS
break;
case 6:
printf("\n The contents of Stack B are :\n");
display_stackB();
break;
}
}while(option != 7);
return 0;
}
Multiple Queues
When we implement a queue using an array, the size of the array must be known in advance. If the queue is allocated less space, then
frequent overflow conditions will be encountered. To deal with this problem, the code will have to be modified to reallocate more
space for the array. In case we allocate a large amount of space for the queue, it will result in sheer wastage of the memory. Thus,
there lies a tradeoff between the frequency of overflows and the space allocated. So a better solution to deal with this problem is to
have multiple queues or to have more than one queue in the same array of sufficient size.
In the figure, an array QUEUE[n] is used to represent two queues, QUEUE A and QUEUE B. The value of n is such that
the combined size of both the queues will never exceed n. While operating on these queues, it is important to note one
thing QUEUE A will grow from left to right, whereas QUEUE B will grow from right to left at the same time. Extending
the concept to multiple queues, a queue can also be used to represent n number of queues in the same array That is, if we
have a QUEUE[n], then each QUEUE I will be allocated an equal amount of space bounded by indices b[i] and e[i]. This
is shown in Fig.
S.TAMILARASAN Page 44
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 45
DATA STRUCTURES AND APPLICATIONS
if(rearA==rearB–1)
printf("\n OVERFLOW");
else
{
if(rearB == MAX && frontB == MAX)
{ rearB = frontB = MAX–1;
QUEUE[rearB] = val;
}
else
QUEUE[––rearB] = val;
}
}
int deleteB()
{
int val;
if(frontB==MAX)
{
printf("\n UNDERFLOW");
return –1;
}
else
{
val = QUEUE[frontB];
frontB––;
if (frontB<rearB)
frontB=rearB=MAX;
return val;
}
}
void display_queueB()
{
int i;
if(frontB==MAX)
printf("\n QUEUE B IS EMPTY");
else
{
for(i=frontB;i>=rearB;i––)
S.TAMILARASAN Page 46
DATA STRUCTURES AND APPLICATIONS
printf("\t %d",QUEUE[i]);
}
}
int main()
{
int option, val;
clrscr();
do
{
printf("\n *******MENU******");
printf("\n 1. INSERT IN QUEUE A");
printf("\n 2. INSERT IN QUEUE B");
printf("\n 3. DELETE FROM QUEUE A");
printf("\n 4. DELETE FROM QUEUE B");
printf("\n 5. DISPLAY QUEUE A");
printf("\n 6. DISPLAY QUEUE B");
printf("\n 7. EXIT");
printf("\n Enter your option : ");
scanf("%d",&option);
switch(option)
{
case 1: printf("\n Enter the value to be inserted in Queue A : ");
scanf("%d",&val);
insertA(val);
break;
case 2: printf("\n Enter the value to be inserted in Queue B : ");
scanf("%d",&val);
insertB(val);
break;
case 3: val=deleteA();
if(val!=–1)
printf("\n The value deleted from Queue A = %d",val);
break;
case 4 : val=deleteB();
if(val!=–1)
printf("\n The value deleted from Queue B = %d",val);
break;
case 5: printf("\n The contents of Queue A are : \n");
S.TAMILARASAN Page 47
DATA STRUCTURES AND APPLICATIONS
display_queueA();
break;
case 6: printf("\n The contents of Queue B are : \n");
display_queueB();
break;
}
}while(option!=7);
getch();
}
A Mazing Problem
A Maze is given as N*N binary matrix of blocks where source block is the upper left most block i.e., maze [0][0] and destination
block is lower rightmost block i.e., maze [N-1][N-1]. A rat starts from source and has to reach destination. The rat can move only in
two directions: forward and down. In the maze matrix, 0 means the block is dead end and 1 means the block can be used in the path
from source to destination. Note that this is a simple version of the typical Maze problem. For example, a more complex version can
be that the rat can move in 4 directions and a more complex version can be with limited number of moves.
Following is an example maze.
Gray blocks are dead ends (value = 0).
S.TAMILARASAN Page 48
DATA STRUCTURES AND APPLICATIONS
Following is the solution matrix (output of program) for the above input matrix.
{1, 0, 0, 0}
{1, 1, 0, 0}
{0, 1, 0, 0}
{0, 1, 1, 1}
All entries in solution path are marked as 1.
Program
/* C/C++ program to solve Rat in a Maze problem using
backtracking */
#include<stdio.h>
// Maze size
#define N 4
bool solveMazeUtil(int maze[N][N], int x, int y, int sol[N][N]);
/* A utility function to print solution matrix sol[N][N] */
void printSolution(int sol[N][N])
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
printf(" %d ", sol[i][j]);
printf("\n");
}
}
return false;
}
/* This function solves the Maze problem using Backtracking. It mainly uses
solveMazeUtil() to solve the problem. It returns false if no path is possible, otherwise
return true and prints the path in the form of 1s. Please note that there may be more than
one solutions, this function prints one of the feasible solutions.*/
S.TAMILARASAN Page 49
DATA STRUCTURES AND APPLICATIONS
S.TAMILARASAN Page 50
DATA STRUCTURES AND APPLICATIONS
sol[x][y] = 0;
return false;
}
return false;
}
// driver program to test above function
int main()
{
int maze[N][N] = { {1, 0, 0, 0},
{1, 1, 0, 1},
{0, 1, 0, 0},
{1, 1, 1, 1}
};
solveMaze(maze);
return 0;
}
S.TAMILARASAN Page 51
DATA STRUCTURES AND APPLICATIONS
Tutorial Questions
1. What do you understand by stack overflow and underflow?
2. Differentiate between an array and a stack.
3. How does a stack implemented using linked lists differ from a stack implemented using an array?
4. Why are parentheses not required in postfix/prefix expressions?
5. What do you understand by a multiple stack? How is it useful?
6. Explain the terms infix expression, prefix expression, and postfix expression. Convert the following infix expressions to their
postfix equivalents:
(a) A – B + C (b) A * B + C / D
(c) (A – B) + C * D / E – C
(d) (A * B) + (C / D) – (D + E)
(e) ((A – B) + D / ((E + F) * G))
(f) (A – 2 * (B + C) / D * E) + F
(g) 14 / 7 * 3 – 4 + 9 / 2
7. Convert the following infix expressions to their postfix equivalents:
(a) A – B + C (b) A * B + C / D
(c) (A – B) + C * D / E – C
(d) (A * B) + (C / D) – ( D + E)
(e) ((A – B) + D / ((E + F) * G))
(f) (A – 2 * (B + C) / D * E) + F
(g) 14 / 7 * 3 – 4 + 9 / 2
8. Explain deque with an example
9. Explain priority queue with an example
10. Explain circular queue.
11. Explain maze problem with an example.
12. Explain Ackerman's function with an example
13. Explain tower of hanoi problem with suitable example
14. Define recursive? Explain how to calculate n factorial using recursion function
15. Explain fibonacci sequence and GCD
16. What do you understand by a multiple queue? How is it useful?
S.TAMILARASAN Page 52