0% found this document useful (0 votes)
13 views16 pages

Queue

Uploaded by

wiekdowow
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views16 pages

Queue

Uploaded by

wiekdowow
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 16

Notes On Algorithms and Data Structures

Queue

A Queue, also called a first-in-first-out (FIFO) structure, is a linear list in which deletions take
place only at one end of the list, the front of the list, and insertions take place only at the other
end of the list, the rear of the list. The features of a Queue are similar to the features of any queue
of customers at a counter, at a bus stop, at railway reservation counter etc. Another common
rear example are buffers for network communication that temporarily store packets of data arriving
front on a network port A queue can be implemented using arrays or linked lists.
Theoretically, a queue does not have a specific capacity. Regardless of how many elements are
already contained, a new element can always be added. For a data structure the executing
computer will eventually run out of memory, thus limiting the queue size. Queue overflow results
from trying to add an element onto a full queue and queue underflow happens when trying to
remove an element from an empty queue. Front always points to the oldest element (inserted first among all elements) in the queue and
rear points to the location where new element to be inserted. A queue is empty when rear and front point to the same location in the
queue.

2.5.1 Implementation of Queue using Array


Queue will be maintained by a linear array Q; a variable front and rear contain the information about the location of the first and the
last element in the queue respectively; and a variable SIZE that gives the maximum number of elements that can be held by the queue.

In order to add new element (i.e. Insert) in the queue it is necessary to check, is there any free space in the array or not after rear, if not,
then this condition is known as queue overflow. In order to delete an element (i.e. delete) from the queue it is necessary to check, is
there an element in the queue or not, if not, then this condition is known as queue underflow. No element in the queue means the queue
is empty. First, let us study the simplest strategy to implement insert an element in a queue and delete an element from a queue.

Insertion operation: In order to add a new element in the queue it is necessary to check where rear is placed. Normally in the beginning,
the rear points to one end of an array and as elements are added to the queue it moves toward the other end of the array. When rear
reaches the other end of the array it indicates that the queue is full and no more insertion is possible.

In the beginning both rear and front points to the 0th location of an array. As elements are inserted rear moves upward and reaches to
the other end of an array. In order to add elements to the queue it is necessary to check queue overflow. Figure 2.10 shows insertion
operations performed on queue. Insertion operation is performed in constant time hence time complexity is O(1).

0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
5 5 7 5 7 3

rea fron rear fron rear fron rear


front
r t 1. Insert 5 in Q t 2. Insert 7 in Q t 3. Insert 3 in Q
Initial Queue Stack
0 1 2 3 4 0 1 2 3 4

6. Insert 10 in Q -- generates 5 7 3 9 8 5 7 3 9
Queue-overflow condition
fron rear fron rear
t 5. Insert 8 in Q t 4. Insert 9 in Q

Figure 2.10. Insertion operations on a Queue of SIZE=5

Following is a code for insertion operation on a queue.


# define SIZE 5
int Q[SIZE], rear= 0, front=0;

void InsQ( int data)


{
if (rear == SIZE)

SIT,Nagpur
Notes On Algorithms and Data Structures

printf("\n Queue is full -- Overflow \n");


else
{
Q[rear]=data;
rear++;
}
}

Table 2.4 shows run of the function InsQ.


Table 2.4. Run of function InsQ
Operation front rear Queue Action
0 0
InsQ(5) 0 0 1 Q[0]=5 Insert element at 0th position
InsQ(7) 0 1 2 Q[0]=5, Q[1]=7 Insert element at 1st position
InsQ(3) 0 2 3 Q[0]=5, Q[1]=7, Q[2]=3 Insert element at 2nd position
InsQ(9) 0 3 4 Q[0]=5, Q[1]=7, Q[2]=3, Q[3]=9 Insert element at 3rd position
InsQ(8) 0 4 5 Q[0]=5, Q[1]=7, Q[2]=3, Q[3]=9, Q[4]=8 Insert element at 4th position
InsQ(10) 0 5 Q[0]=5, Q[1]=7, Q[2]=3, Q[3]=9, Q[4]=8 Queue is full - Queue-Overflow

Deletion operation: Deletion of an element from a queue is only possible if it contains elements otherwise a queue-underflow condition
occurs. If the queue contains elements then elements inserted first will be deleted first. Implementation of insert suggests that the element
inserted first is pointed by front. In order to delete an element from a queue, check stack-underflow condition (front == rear) first, if it
is not then process (or delete) element at front and then increment front. Figure 2.11 shows deletion operations performed on queue.
Deletion operation is performed in constant time hence time complexity is O(1).

0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
5 7 3 9 8 7 3 9 8 3 9 8 9 8

rea fron rear fron rear fron rear


front r 1.t Delete from Q 2. Delete
t from Q 3. Delete from
t Q
Initial Queue

0 1 2 3 4 0 1 2 3 4
6. Delete from Q -- generates
8
Queue-underflow condition

rear fron rear


5. Delete from Q fron 4. Delete fromt Q
t
Figure 2.11. Deletion operations on a Queue of SIZE=5
Following is a code for deletion operation on a queue.
int DelQ()
{
if(front == rear)
printf(" \n Queue is empty -- Underflow\n ");
else
{
return (Q[front++]);
}
}

Table 2.5 shows run of the function DelQ

Table 2.5. Run of function DelQ


Operation front rear Queue Action
SIT,Nagpur
Notes On Algorithms and Data Structures

0 5 Q[0]=5, Q[1]=7, Q[2]=3, Q[3]=9, Q[4]=8


DelQ() 0 1 5 Q[1]=7, Q[2]=3, Q[3]=9, Q[4]=8 Delete element from 0th position
DelQ() 1 2 5 Q[2]=3, Q[3]=9, Q[4]=8 Delete element from 1st position
DelQ() 2 3 5 Q[3]=9, Q[4]=8 Delete element from 2nd position
DelQ() 3 4 5 Q[4]=8 Delete element from 3rd position
DelQ() 4 5 5 Delete element from 4th position
DelQ() 5 5 Queue is empty - Queue-underflow

Traversal operation: The best way to traverse in a queue is to start from the front end and reach up to the rear end. It is not possible to
traverse an empty queue. Following is a code for traversal operation.

void TraverseQ()
{
int i;

if(rear == front)
printf(" \n Queue is empty\n ");
else
{
printf("Traversing in Queue\n");
for(i=front; i< rear; i++)
printf("%d\n", Q[i]);
}
}

The array-based queue is somewhat tricky to implement efficiently. A simple implementation of the array-based queue is not efficient.
Let us consider the case when an array of capacity SIZE is initially empty and SIZE number of elements are inserted into it. These
insertions set the rear at SIZE and now remove all the elements from the queue. These deletions set the front at SIZE. Now one has an
array with no elements but both rear & front are set to SIZE. The condition for queue-full is rear == SIZE hence no more insertion is
possible even though the queue is empty.

Generates Queue-Empty
DelQ() condition
0 1 2 3 4 0 1 2 3 4
5 7 3 9 8
InsQ(10) Generates Queue-Full
rea rear condition
front
r fron
Initial Queue t
There are several possible solutions to solve this problem
1. If at the time of insertion of element in a queue when queue-full condition (rear == SIZE) occurs but queue is not
empty (rear != front) then shift all elements in queue at the beginning of a queue and set front at first element in
queue & rear after the last element of a queue

SIT,Nagpur
Notes On Algorithms and Data Structures

0 1 2 3 4 InsQ(10) 0 1 2 3 4 0 1 2 3 4
Case-1:
3 9 8 3 9 8 3 9 8 10

front rea front rea front rea


r r r

0 1 2 3 4 InsQ(10) 0 1 2 3 4 0 1 2 3 4
Case-2:
10

rear rear front rea


fron fron r
t t
2. Assume that there are n elements in the queue. If the analogy adopted is that all elements of the queue are to be
stored in the first n positions of the array then the first(front) element of the queue is at position 0. DelQ() operation
requires O(n) timebecause the front element of the queue (the one being removed) is the first element in the array.
After removal of the first element in the queue rest of the n-1elements are shifted one position towards the beginning
of the queue. However, InsQ() operation requires O(1) time, because the element is inserted directly at the position
pointedby rear.
0 1 2 3 4 0 1 2 3 4
DelQ()
0 1 2 3 4 7 3 7 3
5 7 3
front rea front rea
r r
front rea InsQ(10) 0 1 2 3 4
r 5 7 3 10
Initial Queue

front rea
r
3. Assume that there are n elements in the queue. If analogy adopted is all elements of the queue are to be stored in the
last n positions of the array then the last element of the queue is at position SIZE-1 & rear is at SIZE. DelQ()
operation requires O(1) time because the front always points to the first element inserted in the queue. InsQ()
operation requires O(n) time, because all the n elements are shifted one position towards the beginning of the queue
(if queue is not full) to create place at the end of array for insertion of element
0 1 2 3 4
DelQ()
0 1 2 3 4 7 3
5 7 3
front rea
r
front rea InsQ(10) 0 1 2 3 4 0 1 2 3 4
r 5 7 3 5 7 3 10
Initial Queue

front rea front rea


r r
1. The “drifting queue” problem can be solved by pretending that the array is circular and so allow the queue to
continue directly from the highest-numbered position in the array to the lowest-numbered position. Implementation
of a circular queue using an array is discussed in the next section.

2.5.2 Circular queues

SIT,Nagpur
Notes On Algorithms and Data Structures

A more efficient queue representation is obtained by an array CQ[ 0 : n-1] as circular. When rear = n-
56 85 1 next element is entered at CQ[0] in case that spot is free using same convention as before front always
points one position counter clockwise from the first element in queue. Again front = rear iff queue is
2 77 91 empty.
Insertion operation: Initially for a circular queue rear=front=0 to indicate the queue is empty. In
55 45 n-
order to add a new element in the queue rear is advanced to the next position in clockwise direction
1 2
25 and if that location is free then an element is added to the queue.
n- rear After adding n-1 elements in the queue any attempt to insert nth element in the queue generates queue-
0
full condition. In order to insert nth element in the queue, rear is advanced to next position but front also
front 1
points to the same location hence now front=rear indicated queue-full condition. In this
implementation, location pointed by front does not store any element hence at the most the queue can accommodate only n-1 elements.
When queue-full occurs it is necessary to restore rear at the last element added in the queue. Figure 2.12 shows insertion operations
performed on a circular queue. Insertion operation is performed in constant time hence time complexity is O(1).

rear
2 2 2 77
Insert 55 Insert 77

n- 55 n- 55 n-
1 2 1 2 1 2
0 n- rear 0 n- 0 n-
rear front 1 front 1 front 1

Figure 2.12. Insertion operations on Circular Queue

Following is a code for insertion operation on a circular queue.


# define SIZE 5
int CQ[SIZE], rear= 0, front=0;

void InsCQ( int data)


{
int t;

t = rear;
rear = (rear + 1) % SIZE;
if (rear == front)
{
printf("\n Circular Queue is full -- Overflow \n");
rear = t;
}
else
CQ[rear] = data;
}

Table 2.6 shows the run of the functions InsCQ

Table 2.6. Run of the functions InsCQ


Operation front rear CQ[0] CQ[1] CQ[2] CQ[3] CQ[4] Action
0 0 Empty Circular Queue
InsCQ(5) 0 0 1 5 Insert element at 1st position
InsCQ(7) 0 1 2 5 7 Insert element at 2nd position
InsCQ(3) 0 2 3 5 7 3 Insert element at 3rd position
InsCQ(9) 0 3 4 5 7 3 9 Insert element at 4th position
InsCQ(8) 0 4 5 7 3 9 Queue is full - Queue-Overflow

SIT,Nagpur
Notes On Algorithms and Data Structures

Deletion operation: Deletion of an element from a queue is only possible if it contains elements otherwise queue-empty condition
occurs. The condition for queue-empty is rear=front. If the queue contains elements then implementation of insertion states
that front always points one position before the first element added in the list in the counterclockwise direction. In order to delete
elements from a queue, advance front by one position in clockwise direction and delete elements at that location. Figure 2.13 shows
deletion operations performed on a circular queue. Deletion operation is performed in constant time hence time complexity is O(1).

56 85 56 85 front 56 85
2 77 2
91 77 91 2 91

55 45 n- Delete 45 n- Delete 45 n-
1 2 1 2 1 2
25 25 25
front
0 n- rear 0 n- rear 0 n- rear
front 1 1 1

Figure 2.13. Deletion operations on Circular Queue

Following is a code for deletion operation on a circular queue.


int DelCQ()
{
if(front == rear)
printf(" \n Circular Queue is empty -- Underflow\n ");
else
{
front = (front +1) % SIZE;
return (CQ[front]);
}
}

Table 2.7 shows run of the function DelCQ and InsCQ.

Table 2.7. Run of the functions DelCQ & InsCQ


Operation front rear CQ[0] CQ[1] CQ[2] CQ[3] CQ[4] Action
0 4 5 7 3 9 Initial Circular Queue
DelCQ() 0 1 4 7 3 9 Delete element from 1st position
DelCQ() 1 2 4 3 9 Delete element from 2nd position
DelCQ() 2 3 4 9 Delete element from 3rd position
DelCQ() 3 4 4 Delete element from 4th position
DelCQ() 4 4 Queue is empty - Queue-underflow
InsCQ(6) 4 4 0 6 Insert element at 0th t position
InsCQ(8) 4 0 1 6 8 Insert element at 1st position
DelCQ() 4 0 1 8 Delete element from 0th position

Traversal operation: best way to traverse in circular queue is to start from the front and move in clock-wise direction till rear comes.
void TraverseCQ()
{
int i;

if(rear == front)
printf(" \n Queue is empty\n ");
else
{
printf("Traversing in Circular Queue\n");
i=front;
do
{

SIT,Nagpur
Notes On Algorithms and Data Structures

i=(i+1) % SIZE;
printf("%d\n", CQ[i]);
}while (i != rear);
}
}

In the circular queue implementation test for Queue-full in InsCQ and test for Queue- empty in DelCQ are the same, that is front = rear.
In implementation when the circular queue is full one memory space is free. If one wishes to insert an element in this free space then
will not be able to distinguish between cases full & empty queue. To avoid this, the implementation is permitting a maximum of n-
1 elements rather than n elements to be in queue at any time.
One way to use all n positions would be to use another variable as tag to distinguish between two situations i.e. tag = 0 if the queue is
empty. This would however slow down two procedures. Since insertion and deletion procedures will be used many-times in many
problems involving queues, loss of one position will be more than made up for reduction in computing time.

int CQ[SIZE], rear= 0, front=0, tag=0;

InsCQB(int data)
{
if (rear == front && tag == 1)
printf("\n Circular Queue is full -- Overflow \n");
else
{
rear = (rear + 1) % SIZE;
if (rear == front)
tag = 1;
CQ[rear] = data;
}
}

DelCQB()
{
if (rear == front && tag == 0)
printf(" \n Circular Queue is empty -- Underflow\n ");
else
{
front = (front +1) % SIZE;
if (front == rear)
tag = 0;
return (CQ[front]);
}
}

void TraverseCQB()
{
int i;

if(rear == front && tag == 0)


printf(" \n Circular Queue is empty\n ");
else
{
printf("Traversing in Circular Queue\n");
i=front;
do
{
i=(i+1) % SIZE;
printf("%d\n", CQ[i]);
}while (i != rear);
}
}

SIT,Nagpur
Notes On Algorithms and Data Structures

Exercise:
1. Suppose a stack implementation supports, in addition, to PUSH and POP, an operation REVERSE, which
reverses the order of the elements on the stack To implement a queue using the above stack implementation,
show how to implement INSERTQ using a single operation and DELETEQ using a sequence of operations.
2. Consider the following sequence of operations on an empty stack.
push(54); push(52); pop(); push(55); push(62); s = pop();
Consider the following sequence of operations on an empty queue.
insertQ(21); insertQ(24); deleteQ(); insert(28); insertQ(32); q = deleteQ();
The value of s + q is ______
3. A letter means insertQ and an asterisk means deleteQ in the following sequence. Give the sequence of values
returned by the deleteQ operations when this sequence of operations is performed on an initially empty queue.
E A S * Y * Q U E * * * S T * * * I O * N * * *
4. Consider the following sequence of stack operations:
insertQ(d), insertQ(h), deleteQ(), insertQ(f), insertQ(s), deleteQ(), deleteQ(), insertQ(m).
Assume the queue is initially empty, what is the sequence of values deleted from the queue, and what is the
final state of the queue?
5. Consider the queues Q1 containing four elements and Q2 containing none (shown as the Initial State in the
figure). The only operations allowed on these two queues are Enqueue (Q, element) and Dequeue (Q). The
minimum number of Enqueue operations on Q1 required to place the elements of Q1 in Q2 in reverse order
(shown as the Final State in the figure) without using any additional storage is ______________.

6. Consider the following statements:


a. First-in-first out types of computations are efficiently supported by STACKS.
b. Implementing LISTS on linked lists is more efficient than implementing LISTS on an array for almost
all the basic LIST operations.
c. Implementing QUEUES on a circular array is more efficient than implementing QUEUES on a linear
array with two indices.
d. Last-in-first-out type of computations are efficiently supported by QUEUES.
Which of these statements are TRUE?
7. Suppose you are given an implementation of a queue of integers. The operations that can be performed on
the queue are:
i. isEmpty (Q) — returns true if the queue is empty, false otherwise.
ii. delete (Q) — deletes the element at the front of the queue and returns its value.
iii. insert (Q, i) — inserts the integer i at the rear of the queue.
Consider the following function:
void f (queue Q) {
int i ;
if (!isEmpty(Q)) {
i = delete(Q);
f(Q);
SIT,Nagpur
Notes On Algorithms and Data Structures

insert(Q, i);
}
}
What operation is performed by the above function f ?
8. Give a recursive implementation of function int queue_size(Q), that takes as input a queue Q and returns the
number of elements in it. Upon returning, the input queue should contain the same elements in the same order
as when it was called. Use the functions provided by the queue interface only.
9. Implement the function a queue_copy(Q); that does return a copy of its input queue.
10. Implement the function queue_reverse(Q); that destructively returns a queue with the same elements as its
input queue but in reverse order. The input queue shall be empty when the call returns.
11. Implement the function void queue_sort(Q), that sorts its input queue. The resulting queue should be sorted
in ascending order, with the largest item at the front and the smallest at the rear. For simplicity, you may
assume that the queue items have type int rather than string. Your code may use temporary queues but no
other data structures. Besides the functions provided by the queue interface. Hint: an effective way to solve
this exercise is carefully consider what loop invariants should hold at various points.
12. What does the following code fragment print when n is 10? In general, what does it do for other positive
integers n? Initially quue is empty.
insert(0);
insert(1);
for (i = 0; i < n; i++) {
a = deleteQ();
print(a);
b = peekQ(); // read the element at front
insertQ(a + b);
}
13.

2.5.3 Priority Queues


Priority queues are a generalization of stacks and queues. Rather than inserting and deleting elements in a fixed order, each element is
assigned a priority and always removes an element with the highest priority.
This is similar to the way patients are waiting in a hospital emergency room. As patients arrive they are evaluated and then placed in a
waiting room. When a doctor becomes available they first treat the patient with the most life-threatening condition.

For example, in an operating system the runnable processes might be stored in a priority queue, where certain system processes are
given a higher priority than user processes. Similarly, in a network router packets may be routed according to some assigned priorities.
In both of these examples, bounding the size of the queues helps to prevent so-called denial-of-service attacks where a system is
essentially disabled by flooding its task store. This can happen accidentally or on purpose by a malicious attacker

Some Implementations
The priority can be assigned to element implicitly or explicitly. Explicitly some integer value is assigned as priority to an element and
then always deletes the element with highest priority. Implicitly some properties of element (like its value) decide priority of element.

There are two types of priority queue possible based on the value of element (priority assigned implicitly)
• Ascending Priority Queue
• Descending Priority Queue
An ascending priority queue is a collection of items into which elements can be inserted arbitrarily and from which only the smallest
value element can be removed. A descending priority queue is similar but allows deletion of only the largest value element.
Considering different implementation choices and consider the complexity of various operations. The intrinsic ordering of the elements
does determine the results of the basic operations. There are several ways to implement ascending priority queue in fixed size (n) array
 Unordered array: Insert element in queue from rear end that is a constant-time operation. However, finding the minimum will
take O(n), since it need scanning of whole portion of the array that’s in use. Consequently, deleting the minimal element also
takes O(n): first find the minimal element, then swap it with the last element in the array, and decrement rear. Figure 2.14
shows insertion & deletion operations performed on priority queue.
SIT,Nagpur
Notes On Algorithms and Data Structures

Initial Queue
0 1 2 3 4 InsQ(10) 0 1 2 3 4
5 3 7 5 3 7 10

front rea front rea


r r
0 1 2 3 4 DelQ() 0 1 2 3 4
Minimum element is at
5 3 7 10 index 1. Swap elements 5 10 7 3
at index 1 and rear
front rea front rea
r r
0 1 2 3 4 0 1 2 3 4
Resultant Decrement
5 10 7 5 10 7 3
Queue rear

front rea front rea


r r
Figure 2.14. Insertion & deletion operations on Priority Queue

 Sorted array: To insert element find quickly (in O(log(n)) steps) the place i where insertion is to be done by using binary
search. Make room for insertion by shifting elements that takes O(n) copy operations. Finding the minimum is O(1) (since it
is stored at index 0 in the array). Deleting the minimum value takes O(1) by keeping the array sorted in descending order, or
by keeping two array indices: one for the smallest current element and one for the largest.

Exercise 2.6:
1. A linear list is being maintained circularly in an array CQ(0: n - 1) with front and rear set up as for circular queues.
a) Obtain a formula in terms of front, rear and n for the number of elements in the list.
b) Write a function to delete the k'th element in the list.
c) Write a function to insert an element Y immediately after the k'th element.
What is the time complexity for b) and c)?

2. A priority queue Q is used to implement a stack S that stores chars, PUSH (c) is implemented as INSERT ( x, c, k) where k is
an appropriate integer key chosen by the implementation POP is implemented as DELETE MIN(k). For a sequence of
operation, the keys chosen one is
(A) non-increasing order (B) non-decreasing order
(C) Strictly increasing order (D) Strictly decreasing order

2.5.4 Double ended Queue


A double ended Queue (deque, DQ) is a linear list in which insertion and deletion may be made at either end.
DQ

front rear

There are two variations of a DQ


 An input-restricted DQ is one where deletion can be made from both ends, but insertion can be made at one end only

SIT,Nagpur
Notes On Algorithms and Data Structures

Input-restricted DQ Input-restricted DQ

front rear front rear

 An output-restricted DQ one where insertion can be made at both ends, but deletion can be made from one end only
Output-restricted DQ Output-restricted DQ

front rear front rear

The operations that can be performed on DQ are


 Insert an element from front end
 Insert an element from rear end
 Delete an element from front end
 Delete an element from rear end
 Display the contents of a queue
The three operations insert from rear, delete from front & display with associated operations to check for an underflow and overflow of
queue have already been discussed in ‘ordinary queue’. Other two operations i.e., insert an element from the front end and delete an
element from the rear end need to be taken care of. For efficient implementation of double ended queue it is better to place rear and
front at the middle of an array in the beginning.

#define SIZE 5
int DQ[SIZE], rear=SIZE/2, front=SIZE/2;

Insertion operation: As elements are added to DQ from either ends, rear and front are moving away from each other (i.e DQ is
expanding). When rear reaches to SIZE insertion from rear end is not possible and when front reaches to -1 insertion from front end is
not possible. In order to add element in DQ it is necessary to check queue overflow. Figure 2.15 shows insertion operations performed
on double ended queue.

0 1 2 3 4 0 1 2 3 4
Initial Queue 3

rea fron rear


r
front t
Figure 2.15. Insertion operation on Double Ended Queue of SIZE=5

DqIns_front(int data)
{
if ( front == -1)
printf(" Insertion not possible from front\n");
else
{
if(rear == front+1)
front--;
DQ[front] = data;
front--;
}

DqIns_rear(int data)
{
if (rear == SIZE)
SIT,Nagpur
Notes On Algorithms and Data Structures

printf(" Insertion not possible from rear\n");


else
{
if(rear == front+1)
rear ++;
DQ[rear] = data;
rear++;
}

Deletion operation: Deletion of element from a double ended queue (DQ) is only possible if it contains elements otherwise queue-
underflow condition occurs. As elements are deleted from either ends of DQ, rear and front are moving towards each other (i.e DQ is
shrinking). DQ is empty if front and rear are equal. Figure 2.16 shows deletion operations performed on double ended queue.

0 1 2 3 4 0 1 2 3 4
Empty 5 3 9
Queue
rea fron rear
r
front t
Figure 2.16. Deletion operation on Double Ended Queue of SIZE=5

DqDel_front()
{
if (front == rear )
printf(" Double Ended Queue is empty\n");
else
{
front++;
if(rear == front+1)
rear--;
}

DqDel_rear()
{
if (rear == front )
printf(" Double Ended Queue is empty\n");
else
{
rear--;
if(rear == front+1)
front++;
}

2.6. Multiple Stacks and Queues

SIT,Nagpur
Notes On Algorithms and Data Structures

Discussion on stack and queue so far concerned only with the


Stack S1 Stack S2
representation of a single stack or single queue in the memory of computer
(i.e. in one-dimensional array). What happens when a data representation n1-1 n2-1 is needed
for several stacks and queues? Multiple stacks and queues can be .. ..
implemented by assigning separate memory to each stack and queue, but ..
this
..
implementation is not very efficient. It may leads to wastage of memory. Let S1 and
S2 are two stacks. It is easy to implement them by assigning separate 1 1 one-
dimensional arrays of SIZE n1 and n2 respectively. Overflow may occur 0 0 when
top top
either stack S1 contains more than n1 elements or stack S2 contains more than n2
elements.

2.6.1 Representation of two stacks in single one-dimensional array


In order to have efficient implementation it is better to represent two stacks in single one-dimensional array. Let X is a one-dimensional
array of size m, where n1, n2 ≤ m ≤ n1+n2. Since there are two ends to array X, one is at index 0 and other is at index m-1. Let stack S1
starts from index 0 & grow in upward direction and stack S2 starts from index m-1 & grow in downward direction. In this case, overflow
will occur only when S1 and S2 together have more than m elements. It does not matter how many elements individually are there in
each stack.

# define SIZE 5
int Stack[SIZE], top1= -1, top2=SIZE;

Push: let top1 and top2 are pointers moving in stacks S1 and S2 respectively. Every insertion
of element in stack S1 increments top1 whereas every insertion of element in S2 decrements Push top2.
Hence after every insertion in stacks top1 and top2 are catching each other and as long as Stack S2 top2 they are
not overlapping or crossing (means top1 < top2) each other it is possible to add elements in both
the stacks. PushS1 is function to add element in stack S 1 and PushS2 is function to add m-1 element
in stack S2. ..
X ..
void PushS1( int data) 1
{
if (top1+1 == top2) 0
printf("\n Stack S1 is full -- Overflow \n");
Stack S1 top1
else
{
top1++;
Stack[top1]=data;
}
}

void PushS2( int data)


{
if (top2-1 == top1)
printf("\n Stack S2 is full -- Overflow \n");
else
{
top2--;
Stack[top2]=data;
}
}

SIT,Nagpur
Notes On Algorithms and Data Structures

Pop: Deletion of element from either stack is only possible if stack contains elements
otherwise stack-underflow condition occurs. If stack contains elements then element inserted Pop last
will be deleted first. Implementation of PushS1 and PushS2 suggests that element inserted last Stack S2 top2 in
stack S1 and S2 is at location the top1and top2 respectively. Every deletion in either stacks moves
m-1
top1 and top2 away from each other. Pointers top1 and top2 are moving towards either ends of the
array. In order to delete element from either stack, check stack-underflow condition first. .. Stack-
underflow (or empty) condition for stack S1 is top1 == -1 and for stack S2 is top2 == SIZE. If X .. stack
is not empty then every deletion of element from stack S1 decrements top1 whereas every 1
deletion of element from S2 increments top2. PopS1 is function to delete element from stack S1 and
0
PopS2 is function to delete element from stack S2.
void PopS1() Stack S1 top1
{
if(top1 == -1)
printf(" \n stack S1 is empty -- Underflow\n ");
else
{
printf(" \n Element deleted from stack S1: %d\n", Stack[top1]);
top1--;
}
}

void PopS2()
{
if(top2 == SIZE)
printf(" \n stack S2 is empty -- Underflow\n ");
else
{
printf(" \n Element deleted from stack S2: %d\n", Stack[top2]);
top2++;
}
}

Traversal operation: Processing of each element in stack can be done by either start from the top and reach up to the bottom of the
stack or start from the bottom of the stack and reach to the top of the stack. TraverseS1 is function to traverse in stack S1 and TraverseS2
is function to traverse in stack S2.
void TraverseS1()
{
int i;

if(top1 == -1)
printf(" \n stack S1 is empty\n ");

else
{
printf("Traversing in Stack S1\n");
for(i= top1; i>-1; i--)
printf("%d\n", Stack[i]);
}
}

void TraverseS2()
{
int i;

if(top2 == SIZE)
printf(" \n stack S2 is empty\n ");

else
{
printf("Traversing in Stack S2\n");
SIT,Nagpur
Notes On Algorithms and Data Structures

for(i= top2; i<SIZE; i++)


printf("%d\n", Stack[i]);
}
}

2.6.2 Representation of multiple stacks in single one-dimensional array


In the case of more than two stacks, stacks cannot be represented in one-dimensional array the same way as did with two stacks. Since
one-dimensional array X has only two fixed points X(0) and X(m-1). Since stack is a single ended abstract data type hence it needs a
bottom marker (BM) to seal the one end. Representations of n stacks need n bottom markers. In order to represent n stacks sequentially
initially divide the available memory X(0:m-1) into n>2 segments. If the sizes of the stacks are known, then, allocate the segments to
them in proportion to the expected sizes of the various stacks. If the sizes of the stacks are not known, then, X(0:m-1) may be divided
into equal segments. For each stack i, use BM (i) to represent a position one less than the position in X for the bottom most element of
that stack. Marker top(i), 0≤ i < n will point to the topmost element of stack i. With roughly equal initial segments BM (i) = top(i) =
(m/n)*i – 1, 0≤ i < n, as the initial values of BM (i) and top (i) as shown in figure 2.17.

(m/n) 2(m/n) m-1


0 -1 -1
….. …..

BM[0] BM[0] BM[0] BM[n]


Top[0 Top[0 Top[0
] ] ]
Figure 2.17. Initial configuration of n stacks in array X[0:m-1], All stacks are empty

For example, in order to represent 3 stacks (i.e. n=3) in an array of size 10 (i.e. m=10), the top and BM for each stacks are initialize as
follows

#define SIZE 10 // Size of array


#define NST 3 // number of stacks

int Stack[SIZE], top[NST]={-1,2,5}, BM[NST+1]={-1,2,5,SIZE-1};

The ith stack grow in lower memory indexes than the (i+1)th stack. The ith stack can grow from BM[i]+1 up to BM[i+1] before it catches
up with the (i=1)th stack.

(m/n) 2(m/n) m-1


0 -1 -1
….. …..

BM[0] BM[0] BM[0] BM[n]


Top[0 Top[0 Top[0
] ] ]
Push: Every insertion of element in ith stack increments ith top by 1. When top of ith stack is equal to BM of (i+1)th stack then no more
insertion is possible in ith stack and it is full.

SIT,Nagpur
Notes On Algorithms and Data Structures

void Push( int i, int data)


{
if (top[i] == BM[i+1])
printf("\n Stack %d is full -- Overflow \n",i);
else
{
top[i]=top[i]+1;
Stack[top[i]]=data;
}
}

Pop: Deletion of element from stack is only possible if stack contains elements otherwise stack-empty condition occurs. Every deletion
of element from ith stack decrements ith top by 1. When top of ith stack is equal to BM of ith stack then no more deletion from ith stack is
possible and it is stack-empty condition.

void Pop(int i)
{
if(top[i] == BM[i])
printf(" \n stack %d is empty -- Underflow\n ",i);
else
{
printf(" \n Element deleted from stack %d: %d\n", i, Stack[top[i]]);
top[i]=top[i]-1;
}
}

Traversal operation: An ith stack can grow from BM[i]+1 up to BM[i+1] and top[i] always points to topmost element in i th stack. Hence
processing of elements in ith stack means visiting elements from top[i] to BM[i]+1.
void Traverse(int i)
{
int j;

if(top[i] == BM[i])
printf(" \n stack %d is empty\n ",i);

else
{
printf("Traversing in Stack %d\n",i);
for(j= top[i]; j>BM[i]; j--)
printf("%d\n", Stack[j]);
}
}

SIT,Nagpur

You might also like