DSA Module2 Notes Full
DSA Module2 Notes Full
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 1
Data Structures and Applications (23CS204) Module 2
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 2
Data Structures and Applications (23CS204) Module 2
Algorithm
1. Checks if the stack is full.
2. If the stack is full, produces an error and exit.
3. If the stack is not full, increments top to point next empty space.
4. Adds data element to the stack location, where top is pointing.
5. Returns success.
Code:
void push(int item)
{
/* add an item to the global stack */
if (top >= MAX_STACK_SIZE – 1)
printf(“Overflow error!!! Item cannot be added to the stack.”);
else
{
++top;
stack[top] = item;
}
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 3
Data Structures and Applications (23CS204) Module 2
Code
int pop()
{
/* delete and return the top element from the stack */
if (top == -1)
{
printf(“Underflow error!!!\n”);
return -999;
}
else
return stack[top--];
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 4
Data Structures and Applications (23CS204) Module 2
Algorithm
1. Checks if the stack is empty.
2. If the stack is empty, produces an error and exit.
3. If the stack is not empty, returns the data element at which top is pointing.
4. Returns success.
Code
int top()
{
/* return the top element of the stack */
if (top == -1)
{
printf(“Stack is empty!\n”);
return -999;
}
else
return stack[top];
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 5
Data Structures and Applications (23CS204) Module 2
Code
int isfull()
{
if (top == MAX_STACK_SIZE)
return 1;
else
return 0;
}
Algorithm
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 6
Data Structures and Applications (23CS204) Module 2
1. START
2. If the top value is -1, the stack is empty. Return 1.
3. Otherwise, return 0.
4. END
Code
int isEmpty()
{
if (top == -1)
return 1;
else
return 0;
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 7
Data Structures and Applications (23CS204) Module 2
Minimizing Overflow
There is an essential difference between underflow and overflow in dealing with stacks.
Underflow depends exclusively upon the given algorithm and the given input data, and hence
there is no direct control by the programmer. Overflow, on the other hand, depends upon
the arbitrary choice of the programmer for the amount of memory space reserved for each
stack, and this choice influences the number of times overflow may occur.
The choice of the amount of memory space reserved for each stack involves a time-
space tradeoff. Initially reserving a great deal of space for each stack will decrease the number
of times overflow may occur; but this may be an expensive use of the space if most of the
space is seldom used. On the other hand, reserving a small amount of space for each stack
may increase the number of times overflow occurs; and the time required for resolving an
overflow may be more expensive than the space saved.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 8
Data Structures and Applications (23CS204) Module 2
We can overcome this shortcoming by using a dynamically allocated array for the elements
and then increasing the size of this array as needed.
The following are the changes in the array implementation:
#define max 10
int *stack;
stack=(int *)malloc(max*sizeof(int));
void push(int ele)
{
if(top==max-1)
{
max=2*max;
printf("stack overflow so stack is resized and element is pushed\n");
a=realloc(a,max*sizeof(int));
}
a[++top]=ele;
}
2.7 Applications of stacks:
1) System stack: The system stack is a special stack that is used by a program at run-
time to process function calls.
Whenever a function is invoked, the program creates a structure, referred to as an
activation record or a stack frame, and places it on top of the system stack. Initially, the
activation record for the invoked function contains only a pointer to the previous stack
frame and a return address. The previous stack frame pointer points to the stack frame of
the invoking function, while the return address contains the location of the statement to
be executed after the function terminates. Since only one function executes at any given
time, the function whose stack frame is on top of the system stack is chosen (Fig. 2.10).
If this function invokes another function, the local variables, except those declared static,
and the parameters of the invoking function are added to its stack frame. A new stack
frame is then created for the invoked function and placed on top of the system stack. When
this function terminates, its stack frame is removed and the processing of the invoking
function, which is again on top of the stack, continues.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 9
Data Structures and Applications (23CS204) Module 2
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 10
Data Structures and Applications (23CS204) Module 2
We assume that in any parenthesis-free expression, the operations on the same level are
performed from left to right. (However, some languages perform exponentiations from right
to left.)
Example: Evaluate the parent
esis-free arithmetic expression:
2 ^ 3 + 5 * 2 ^ 2 – 12 / 6.
Solution: 2 ^ 3 + 5 * 2 ^ 2 – 12 / 6 = 8 + 5*4 – 12 / 6 = 8 + 20 – 2 = 26
Thus, the expression is traversed three times, each time corresponding to a level of
precedence of the operations.
For most arithmetic operations the operator symbol is placed between its two operands. This
is also called infix notation; Eg. A + B, C-D, E * F, G / H.
We must distinguish between
(A + B) * C and A + (B*C)
by using parenthesis or some operator-precedence. Thus, the order of the operators and
operands in an arithmetic expression does not uniquely determine the order in which the
operations are to be performed.
Polish Notation:
Named after the polish mathematician Jan Lukasiecthewicz, Polish notation refers to the prefix
notation. Here the operator symbol is placed before its two operands. The fundamental
property of the Polish notation is that the order in which the operations are to be performed
is completely determined by the positions of the operators and operands in the expression.
Ex.: +AB, -CD, *EF, /GH
Example: Translate the following infix expressions into Polish notation using brackets[] to
indicate a partial translation:
i) (A + B) * C = [+AB]*C = *+ABC
ii) A + (B * C) = A + [*BC] = +A*BC
iii) (A+B)/(C-D) = [+AB]/[-CD] = /+AB-CD
iv) (A-B) * (C+D) = [-AB] * [+CD] = *-AB+CD
v) (A+B) / (C+D) – (D*E)
[+AB] / [+CD] – [*DE]
[/+AB+CD] – [*DE]
-/+AB+CD*DE
Reverse Polish notation refers to the notation in which the operator symbol is placed after
its two operands. Ex.: AB+, CD- EF*, GH/.
One never needs parenthesis to determine the order of the operations in any arithmetic
expression written in reverse Polish notation. This notation is also called as postfix or suffix
notation.
Example: Convert the following infix expressions into postfix expressions.
a) (A - B) * (C + D) b) (A + B) / (C + D) – (D * E)
Solution:
a) (A - B) * (C + D) [AB-] * [CD+]
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 11
Data Structures and Applications (23CS204) Module 2
The computer usually evaluates an expression written in infix notation in two steps:
i) It converts the expression to postfix expression.
ii) It evaluates the postfix expression.
In both these steps, the stack is the main tool.
b) (A + B) / (C + D) – (D * E)
[AB+] / [CD+] – [DE*]
[AB+CD+/] – [DE*]
AB+CD+/DE*-
2.9.1 Algorithm
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 12
Data Structures and Applications (23CS204) Module 2
The following algorithm transforms the infix expression Q into its equivalent postfix expression P.
The algorithm uses a stack to temporarily hold operators and left parenthesis. The expression P will
be constructed from left to right using the operands from Q and the operators removed from the
STACK. We begin by pushing a left parenthesis onto STACK and adding a right parenthesis at the
end of Q. The algorithm is completed when the STACK is empty.
Algorithm: POLISH(Q, P): Suppose Q is an arithmetic expression written in infix notation. This
algorithm finds the equivalent postfix expression P.
STEP 1: Push “(“ onto STACK, and add “)” to the end of Q.
STEP 2: Scan Q from left to right and repeat steps 3 to 6 for each element of Q until the STACK is
empty.
STEP 3: If an operand is encountered, add it to P.
STEP 4: If a left parenthesis is encountered, push it onto STACK.
2.9.2 Examples:
Example: Convert the following arithmetic infix expression Q to postfix expression using the algorithm.
Q: A + (B * C – (D / E ^ F) * G) * H
Solution: First we push “(“ onto STACK and then we add “)” to the end of Q and obtain:
Q: A + (B * C – (D / E ^ F) * G) * H )
Symbol Scanned STACK Expression P
(
A ( A
+ (+ A
( (+( A
B (+( AB
* (+(* AB
C (+(* ABC
- (+(- ABC*
( (+(-( ABC*
D (+(-( ABC*D
/ (+(-(/ ABC*D
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 13
Data Structures and Applications (23CS204) Module 2
E (+(-(/ ABC*DE
^ (+(-(/^ ABC*DE
F (+(-(/^ ABC*DEF
) (+(- ABC*DEF^/
* (+(-* ABC*DEF^/
G (+(-* ABC*DEF^/G
) (+ ABC*DEF^/G*-
* (+* ABC*DEF^/G*-
H (+* ABC*DEF^/G*-H
) ABC*DEF^/G*-H*+
Example: Convert the following infix expression into postfix expression using the algorithm.
Q: A – (B / C + (D % E * F) / G)* H)
After adding the ),
Q: A – (B / C + (D % E * F) / G)* H) )
Applying the algorithm, we get
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 14
Data Structures and Applications (23CS204) Module 2
Example: Convert the following infix expression into postfix expression using the algorithm:
(A+B^D)/(E-F)+G
After adding the sentinel,
(A+B^D)/(E–F)+G )
Applying the algorithm, we get
Symbol Scanned STACK Expression P
(
( ((
A (( A
+ ((+ A
B ((+ AB
^ ((+^ AB
D ((+^ ABD
) ( ABD^+
/ (/ ABD^+
( (/( ABD^+
E (/( ABD^+E
- (/(- ABD^+E
F (/(- ABD^+EF
) (/ ABD^+EF-
+ (+ ABD^+EF-/
G (+ ABD^+EF-/G
) ABD^+EF-/G+
Thus, the equivalent postfix expression is: ABD^+EF-/G+
2.9.3 Program in C
#include<stdio.h>
#include<string.h>
char stack[20];
int top=-1;
void push(char s)
{
stack[++top]=s;
}
char pop()
{
return stack[top--];
}
int precd(char s)
{
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 15
Data Structures and Applications (23CS204) Module 2
switch(s)
{
case '^': return 4;
case '*':
case '/': return 3;
case '+':
case '-': return 2;
case '(':
case ')':
case '#':return 1;
}
return 0;
}
void infixToPostfix(char infix[20], char postfix[20])
{
int i,j=0,n;
char symbol;
n = strlen(infix);
push('#');
for(i=0;i<n;i++)
{
symbol=infix[i];
switch(symbol)
{
case '(': push(symbol);
break;
case ')': while(stack[top]!='(')
postfix[j++]=pop();
pop();//pop ( bracket
break;
case '^':
case '*':
case '/':
case '+':
case '-': while(precd(symbol)<=precd(stack[top]))
postfix[j++]=pop();
push(symbol);
break;
default:postfix[j++]=symbol;
}
}
while(stack[top]!='#')
postfix[j++]=pop();
postfix[j]='\0';
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 16
Data Structures and Applications (23CS204) Module 2
int main()
{
char infix[20],postfix[20];
printf("\n Enter infix expression: ");
gets(infix);
infixToPostfix(infix,postfix);
printf("postfix expr is\n %s",postfix);
return 0;
}
2.10.1 Algorithm
Algorithm: This algorithm finds the value of an arithmetic expression P written in postfix notation.
Step 1: Add a right parenthesis “)” at the end of P. [This acts as a sentinel.]
Step 2: Scan P from left to right and repeat Steps 3 and 4 for each element of P until the sentinel
“)” is encountered.
Step 3: If an operand is encountered, push it on STACK.
Step 4: If an operator is encountered, then:
a) Remove the two top elements of STACK, where A is the top element and
B is the next-to-top element.
b) Evaluate B A.
c) Push the result of (b) back on STACK.
[End of If structure]
[End of Step 2 loop.]
Step 5: Set VALUE equal to the top element on STACK.
Step 6: Exit.
When Step 5 is executed, there should be only one number on STACK.
2.10.2 Examples
Example: Consider the following arithmetic expression P written in postfix notation:
P: 5, 6, 2, +, *, 12, 4, /, -
Commas are used to separate the elements of P so that 5, 6, 2 is not interpreted as the number 562. The
equivalent infix expression Q is: 5 * (6 + 2) – 12 / 4.
Adding the sentinel, the expression P becomes: 5, 6, 2, +, *, 12, 4, /, -, )
Evaluating using the algorithm, we get:
Symbol Scanned STACK
5 5
6 5, 6
2 5, 6, 2
+ 5, 8
* 40
12 40, 12
4 40, 12, 4
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 17
Data Structures and Applications (23CS204) Module 2
/ 40, 3
- 37
)
The final value in the STACK, 37, is the value assigned to VALUE when the sentinel ‘)’ is scanned, is the
value of P.
Example: Convert the infix expression 9 – ((3 * 4) + 8) / 4 into postfix expression and evaluate the
same.
Solution: Infix expression: 9 – ((3 * 4) + 8) / 4
9 – ([3 4 *] + 8) / 4
9 – [3 4 * 8 +] / 4
9 – [3 4 * 8 + 4 /]
934*8+4/-
The postfix expression is: 9 3 4 * 8 + 4 / -
Adding the sentinel, the expression becomes: 9 3 4 * 8 + 4 / - $
Evaluating the expression using the algorithm, we get:
2.10.3 Code in C
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
float stack[20];
int top=-1;
void push(float ele)
{
stack[++top]=ele;
}
float pop()
{
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 18
Data Structures and Applications (23CS204) Module 2
return(stack[top--]);
}
float evaluate(char postfix[50])
{
int i;
char sym;
float op1,op2,result;
for(i=0;i<strlen(postfix);i++)
{
sym=postfix[i];
if(isdigit(sym))
push(sym-'0');
else
{
op2=pop();
op1=pop();
switch(sym)
{
case '+':push(op1+op2);
break;
case '-':push(op1-op2);
break;
case '*':push(op1*op2);
break;
case '/':push(op1/op2);
break;
case '%':push((int)op1%(int)op2);
break;
case '^':push(pow(op1,op2));
break;
default:printf("invalid postfix expression");
exit(0);
}
}
}
result = pop();
return(result);
}
int main()
{
char postfix[50];
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 19
Data Structures and Applications (23CS204) Module 2
float ans;
printf("enter the postfix expression\n");
gets(postfix);
ans = evaluate(postfix);
printf("the result is %f\n",ans);
}
2.11.2 Implementation in C
/* C Program to Implement two Stacks using a Single Array and Check for Overflow and Underflow */
#include <stdio.h>
#define MAX_STACK_SIZE 20
int stack[MAX_STACK_SIZE]; // declaration of array type variable.
int top1 = -1;
int top2 = MAX_STACK_SIZE;
//Function to push data into stack1
void push1 (int data)
{
// checking the overflow condition
if (top1 < top2 - 1)
{
top1++;
stack[top1] = data;
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 20
Data Structures and Applications (23CS204) Module 2
}
else
printf ("Stack is full");
}
// Function to push data into stack2
void push2 (int data)
{
// checking overflow condition
if (top1 < top2 - 1)
{
top2--;
stack[top2] = data;
}
else
printf ("Stack is full..\n");
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 21
Data Structures and Applications (23CS204) Module 2
{
int i;
for (i = top1; i >= 0; --i)
printf ("%d ", stack[i]);
printf ("\n");
}
// Function to print the values of Stack2
void display_stack2 ()
{
int i;
for (i = top2; i < MAX_STACK_SIZE; ++i)
printf ("%d ", stack[i]);
printf ("\n");
}
int main()
{
int stack[MAX_STACK_SIZE];
int i;
int num_of_ele;
printf ("We can push a total of 20 values\n");
//Number of elements pushed in stack 1 is 10
//Number of elements pushed in stack 2 is 10
// loop to insert the elements into Stack1
for (i = 1; i <= 10; ++i)
{
push1(i);
printf ("Value Pushed in Stack 1 is %d\n", i);
}
// loop to insert the elements into Stack2.
for (i = 11; i <= 20; ++i)
{
push2(i);
printf ("Value Pushed in Stack 2 is %d\n", i);
}
//Print Both Stacks
display_stack1 ();
display_stack2 ();
//Pushing on Stack Full
printf ("Pushing Value in Stack 1 is %d\n", 11);
push1 (11);
//Popping All Elements from Stack 1
num_of_ele = top1 + 1;
while (num_of_ele)
{
pop1 ();
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 22
Data Structures and Applications (23CS204) Module 2
--num_of_ele;
}
// Trying to Pop the element From the Empty Stack
pop1 ();
return 0;
}
Output:
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 23
Data Structures and Applications (23CS204) Module 2
Assuming that we have n stacks, we can divide the available memory into n segments. This initial division
may be done in proportion to the expected sizes of the various stacks, if this is known. Otherwise, we
may divide the memory into equal segments.
Assume that i refers to the stack number of one of the n stacks. To establish this stack, we must create
indices for both the bottom and top positions of this stack. The convention we use is that
boundary [i], 0 ≤ i < MAX_STACKS, points to the position immediately to the left of the bottom element
of stack i,
top[i], 0 ≤ i < MAX_STACKS, points to the top element of stack i.
Stack i is empty iff boundary[i] = top[i].
To divide the array into roughly equal segments we use the following code:
top[0] = boundary[0] = -1;
for (j = 1; j < n; j++)
top[jJ = boundary[j] = (MAX_STACK_SIZE /n) * j - 1;
boundary[n] = MAX_STACK_SIZE - 1;
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 24
Data Structures and Applications (23CS204) Module 2
if (top[i] == boundary[i+1] )
stackFull(i);
memory[++top[i]] = item;
}
2.12 Recursion
Recursion is an important concept in Computer Science. Many algorithms can be best described in terms
of recursion.
2.12.1 Definition
Suppose P is a procedure containing either a call statement to itself or a call statement to a second
procedure that may eventually result in a call statement back to the original procedure P, then P is called
a recursive procedure. Since a recursive procedure should not run indefinitely, it must have the
following two properties:
1) There must be certain criteria, called base criteria, for which the procedure does not call itself.
2) Each time the procedure calls itself (directly or indirectly), it must be closer to the base criteria.
A recursive procedure with these two properties is said to be well-defined.
The steps of a recursive program are:
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.
Suppose P is a recursive procedure. When an algorithm or program that contains P is run, a level
number is associated with each execution of procedure P. The original execution of P is assigned level
1; each time P is executed because of a recursive call, its level is one more than the level of execution
that has made the recursive call.
The depth of recursion of a recursive procedure P with a given set of arguments refers to the
maximum level number of P during its execution.
2! = 1 . 2 = 2
3! = 1 . 2. 3 = 6
n! = n . (n-1)!
Accordingly, the factorial function may also be defined as:
a) If n = 0, then n! = 1.
b) If n > 0, then n! = n.(n-1)!
In this definition of n!,
i) It refers to itself.
ii) The value of n! is explicitly given when n = 0; 0 is the base value.
iii) The value of n! for arbitrary n is defined in terms of a smaller value of n which is closer to the base
value 0.
So, the procedure is well-defined.
Example:
Calculate 4! Using the recursive definition, this calculation requires nine steps.
Step 1: 4! = 4 . 3!
Step 2: 3! = 3 . 2!
Step 3: 2! = 2 . 1!
Step 4: 1! = 1 . 0!
Step 5: 0! = 1
Step 6: 1! = 1 . 1 = 1
Step 7: 2! = 2. 1 =2
Step 8: 3! = 3 . 2 = 6
Step 9: 4! = 4 . 6 = 24
That is, in step 5 we evaluate the base value 0!. In steps 6 to 9, we backtrack, using 0! we find 1!, using
1! we find 2!, using 2! we find 3! and finally, using 3!, we find 4!.
The advantages of recursion pay off for the extra overhead involved in terms of time and space
required.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 26
Data Structures and Applications (23CS204) Module 2
2.12.2 Algorithm
Rather than finding a separate solution, we use the technique of recursion to develop a general solution.
Here is a high-level outline of how to move n disks from the peg A, to peg C, using an auxiliary /
intermediate peg, peg B:
1. Move the top n-1 disks from the original peg A to the auxiliary peg B, using the final peg C.
2. Move the remaining disk from the original peg A to the final peg C.
3. Move the n-1 disks from the auxiliary peg B to the final peg C using the original peg A.
Each of the three subproblems listed in steps 1 to 3 may be solved directly or is essentially the
same as the original problem using fewer disks.
The only thing missing from the outline above is the identification of a base case. The simplest
Tower of Hanoi problem is a tower of one disk. In this case, we need move only a single disk to its final
destination i.e. from the original peg A to the final peg C – this is the base case.
The steps outlined above move us toward the base case by reducing the number of disks in steps
1 and 3 (Fig.2.14). Thus, this reduction process yields a recursive solution to the Tower of Hanoi problem.
2.12.4 Code in C
#include<stdio.h>
int count=0;
void TowerofHanoi(int n, char s, char t, char d)
{
if(n==1)
{
printf("move from %c to %c\n",s,d);
count++;
}
else
{
TowerofHanoi(n-1, s,d,t);
printf("move from %c to %c\n",s,d);
count++;
TowerofHanoi(n-1, t,s,d);
}
}
int main()
{
int n;
printf("enter the number of disks\n");
scanf("%d",&n);
TowerofHanoi(n,'S','T','D');
printf("no of moves=%d\n",count);
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 28
Data Structures and Applications (23CS204) Module 2
The simplest representation of a queue is a one-dimensional array and two variables, front and rear. The
front and rear variables point to the position from where deletions and insertions can be done,
respectively.
A real-world example of queue can be a single-lane one-way road (Fig. 2.15), where the vehicle enters
first, exits first. More real-world examples can be seen as queues at the ticket windows and bus-stops.
Consider the queue shown in Fig. 2.17. Here, front = 0 and rear = 5.
If we want to add one more value to the list, say, if we want to add another element with the value 45,
then the rear would be incremented by 1 and the value would be stored at the position pointed by the
rear. The queue, after the addition, would be as shown in Fig. 2.18. Here, front = 0 and rear = 6.
Every time a new element is to be added, we will repeat the same procedure.
However, before inserting an element in the queue, we must check for overflow condition. An overflow
occurs when we try to insert an element into a queue that is already full.
A queue is full when rear = MAX – 1, where MAX is the size of the queue, that is MAX specifies the
maximum number of elements in the queue. Note that we have written MAX – 1 because the index starts
from 0.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 29
Data Structures and Applications (23CS204) Module 2
Now, if we want to delete an element from the queue, then the value of front will be incremented.
Deletions are done only from this end of the queue. The queue after the deletion will be as shown in Fig.
2.19.
2.16.2 Declarations
The declarations for the one-dimensional array implementation of queue:
Queue CreateQ(maxQueueSize) ::=
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 30
Data Structures and Applications (23CS204) Module 2
2.16.3 Operations
The queue operations for the one-dimensional array representation are as follows:
Boolean lsEmptyQ(queue) ::= front == rear
Boolean IsFullQ(queue) ::= rear == MAX_QUEUE_SIZE-1
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 31
Data Structures and Applications (23CS204) Module 2
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 32
Data Structures and Applications (23CS204) Module 2
As jobs enter and leave the system, the queue gradually shifts to the right. This means that eventually
the rear index equals MAX-QUEUE-SIZE - 1, indicating that the queue is full. In this case, queueFull
should move the entire queue to the left so that the first element is again at gueue[0] and front is at -1.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 33
Data Structures and Applications (23CS204) Module 2
It should also recalculate rear so that it is correctly positioned. Shifting an array is very time-consuming,
particularly when there are many elements in it. In fact, queueFull has a worst case complexity of
O(MAX_QUEUE_SIZE).
In a circular queue, the convention for variable front is changed. Variable front represents one
position before the front element in the queue. The convention for rear is unchanged i.e. variable
rear represents the rear element in the queue. This change simplifies the codes slightly.
- When the array is viewed as a circle, each array position has a next and a previous position.
- The position next to position MAX_QUEUE_SIZE-1 is 0, and the position that precedes 0 is
MAX_QUEUE_SIZE- 1.
- When the queue rear is at MAX_QUEUE_SIZE- 1, the next element is put into position 0.
- To work with a circular queue, we must be able to move the variables front and rear from their current
position to the next position (clockwise). This may be done using code such as
if (rear == MAX_QUEUE_SIZE - 1) rear = 0;
else rear++;
- This code is equivalent to
(rear+1) % MAX_QUEUE_SIZE.
Illustration:
To delete an element, we advance front one position clockwise and to add an element, we advance rear
one position clockwise and insert at the new position.
If we perform 3 deletions from the queue of Fig. 2.23 in this fashion, the queue becomes empty and that
front = rear.
When we do 5 additions to the queue of Fig. 2.23, the queue becomes full and front = rear.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 34
Data Structures and Applications (23CS204) Module 2
2.19.2 Declarations
The declarations for the one-dimensional array implementation of a circular queue:
Queue CreateQ(maxQueueSize) ::=
#define MAX_QUEUE_SIZE 100 /* maximum queue size */
typedef struct
{
int key;
/* other fields */
} element;
element queue[MAX_QUEUE_SIZE] ;
int rear = front = 0;
4. END
Code
bool isEmpty()
{ // Checks whether the queue is empty or not:
return (front == rear);
}
Observe that the test for a full queue in addq and the test for an empty queue in deleteq are the same.
In the case of addq, however, when front == rear is evaluated and found to be true, there is actually one
space free (queue[rear]) since the first element in the queue is not at queue[front] but is one position
clockwise from this point. If we insert an item here, then we will not be able to distinguish between the
cases of full and empty, since the insertion would leave front equal to rear. To avoid this we signal queue
Full, thus permitting a maximum of MAX_QUEUE_SIZE-1 elements in the queue rather than
MAX_QUEUE_SIZE elements in the queue at any time.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 36
Data Structures and Applications (23CS204) Module 2
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 37
Data Structures and Applications (23CS204) Module 2
The following function gives the code to add to a circular queue using a dynamically allocated array.
void addq(element item)
{
/* add an item to the dynamic circular queue */
rear = (rear + 1) % capacity;
if (front == rear)
queueFull(); /* double capacity */
queue[rear] = item;
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 38
Data Structures and Applications (23CS204) Module 2
The following function gives the code for queueFull, that obtains the configuration of Fig. 2.25(e). The
function copy(a,b,c) copies elements from locations a through b-1 to locations beginning at c.
void queueFull()
{
/* Doubling queue capacity - allocate an array with twice the capacity */
element* newQueue;
int start;
newQueue = (element *) malloc(2*capacity*sizeof(*queue));
/* switch to newQueue */
front = 2*capacity – 1;
rear = capacity – 2;
capacity *= 2;
free(queue);
queue = newQueue;
}
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 41
Data Structures and Applications (23CS204) Module 2
• Efficient algorithms can be implemented. Priority queues are used in many algorithms to improve
their efficiency, such as Dijkstra’s algorithm for finding the shortest path in a graph and the A*
search algorithm for pathfinding.
• Included in real-time systems. This is because priority queues allow you to quickly retrieve the
highest priority element, they are often used in real-time systems where time is of the essence.
Disadvantages of Priority Queue:
• High complexity. Priority queues are more complex than simple data structures like arrays and
linked lists, and may be more difficult to implement and maintain.
• High consumption of memory. Storing the priority value for each element in a priority queue can
take up additional memory, which may be a concern in systems with limited resources.
• It is not always the most efficient data structure. In some cases, other data structures like heaps
or binary search trees may be more efficient for certain operations, such as finding the minimum
or maximum element in the queue.
• At times it is less predictable:. This is because the order of elements in a priority queue is
determined by their priority values, the order in which elements are retrieved may be less
predictable than with other data structures like stacks or queues, which follow a first-in, first-out
(FIFO) or last-in, first-out (LIFO) order.
Notes prepared by Dr. Josephine Prem Kumar, Prof.-CSE, Cambridge Institute of Technology, Bangalore 2024-25 42