0% found this document useful (0 votes)
3 views46 pages

SESS-3 Stack Queue

This document provides an overview of stacks and queues, including their definitions, operations, and implementations using arrays and linked lists. It explains the Last In First Out (LIFO) nature of stacks and the First In First Out (FIFO) nature of queues, along with their respective Abstract Data Types (ADTs). The document also includes algorithms and example programs for implementing stacks using both arrays and linked lists.

Uploaded by

Arun Sinha
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)
3 views46 pages

SESS-3 Stack Queue

This document provides an overview of stacks and queues, including their definitions, operations, and implementations using arrays and linked lists. It explains the Last In First Out (LIFO) nature of stacks and the First In First Out (FIFO) nature of queues, along with their respective Abstract Data Types (ADTs). The document also includes algorithms and example programs for implementing stacks using both arrays and linked lists.

Uploaded by

Arun Sinha
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/ 46

Stacks And Queues

Stacks And Queues


3
At the end of this chapter you will be able to understand the concept of stacks and
queues and implement them in your programs.

SCOPE
3.1 Introduction

3.2 ADT of Stacks

3.3 Implementation
3.3.1 Using Arrays
3.3.2 Using Linked Lists

3.4 Analysis of Stack implementations

3.5 Examples

3.6 ADT of Queues

3.7 Queue implementations


3.7.1 Using Arrays
3.7.2 Using Linked Lists

3.8 Analysis of Queue implementations

3.9 Other type of Queues

3.10 Examples

3.11 Application

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 69
Stacks And Queues

3.1 Introduction
Try answering the following questions: What data structure would you use if you want to
execute the most recently submitted program to be executed first in a sequence of
programs? Similarly, what data structure would you use if you want to execute the
programs in the same order that they were submitted.
In our ensuing session we will try to answer questions like these.

In our daily life, we often see a pile of boxes kept one over another. We keep adding
more boxes, but we can do so only at the top. Also, we can remove the boxes only from
the top and not from bottom or from in between. Also, we have seen a queue of
passengers on a railway counter. The first person in the queue will get the ticket first.
Any new passenger will have to stand behind the last in the queue i.e. at the end.

In computing paradigm, there are several situations when certain things have to be done
in a particular order. For example, if programs p1, p2, p3 and p4 are submitted to the
operating system of a computer in the following order:

1. p1
2. p2
3. p3
4. p4

The operating system may execute these programs in the above order only, i.e. p1 first
and p4 last. Else, the operating system may execute these programs in the opposite order,
i.e. p4 first and p1 last.

Stacks and Queues are two very common and important data structures used in such
situations.

A stack is an ordered list in which all insertions and deletions are done at one end, called
the top.

A queue is an ordered list in which all insertions take place at one end, the rear, while all
deletions take place at the other end, the front.

Given a stack S={a1, a2, a3, ------an}, we say that a1 is the bottommost element
and element ‘ai’ is on the top of element a(i-1),1<=i<=n.

In a queue, let an is the rear element and a(i+1) is behind ai,1<=i<n. To understand
this more clearly, have a look at the fig. 3.1.

Chapter 3
70 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

rear front
a[5] E top
a[4] D
F E D C B A
a[3] C
a[2] B
a[1] A a[6] a[5] a[4] a[3] a[2] a[1]

STACK

Fig.3.1
A Stack and a Queue

As shown in the figure, in the stack element a[2] is on the top of a[1], element a[3] is
on the top of a[2], and so on. Similarly, In the queue a[2] is behind a[1], a[3] is
behind a[2], and so on.

Every data structure has some constraints or restrictions which dictate that the particular
data structure be treated in a particular manner. The restrictions on stacks mean that the
first element to be removed will be the top element. Also, the last element to be inserted
into the stack will be the first to be removed.

For example, take a look at the figure 3.1. If you want to add ‘F’, it will be added over
‘E’. Also, now if you want to remove an element from the stack, ‘F’ has to be removed
first. Therefore stacks are called Last In First Out (LIFO) lists.

The restrictions on the queues mean that the first element to be inserted will be the first to
be removed. For example, if you want to add ‘G’ in the above queue, it will come after
‘F’, but if you want to take one element out, it will be ‘A’, i.e. the first element in the
queue.

Therefore, queues are also called First In First Out (FIFO) lists.

The definition of stacks and queues provide for the insertion and deletion of items. So,
stacks and queues are dynamic, constantly changing objects. There is no upper limit on
the number of items that may be kept in a stack, since the definition does not specify how
many items are allowed in the collection. Pushing another item on the stack or a queue
merely produces a larger collection of items. How many elements can be stored in a
particular data structure is purely a matter of implementation.

A stack or a queue is considered an “ordered” group of items because elements occur in a


sequence according to how long they have been in the stack.

For example, the topmost item in a stack has been in the stack for the shortest time and
the bottommost for the longest time. Similarly, the front item in the queue has been there
for the longest time and the rear is the most recently added.

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 71
Stacks And Queues

Queues provide a rather different pattern of data storage and retrieval than is found with
stacks. In particular, once an item is placed on a queue, the item is not retrieved until all
items ahead of it have been removed. Here, the first item placed into a queue is the first to
be processed and subsequent items must wait for their turn. Therefore, queues provide
FIFO storage as opposed to LIFO storage provided by stacks.

3.2 ADT of Stacks


A stack is a dynamic structure i.e. it changes as elements are added to and removed from
it. The operation that adds an element to the top of a stack is usually called PUSH and the
operation that takes the top element off the stack is called POP. When we start using the
stack for the first time, it must be empty, so we need to create an empty stack. We must
also have an operation to check whether a stack has something in it to pop or not. For
particular implementations one may need to check whether a stack is full or not. ADT of
such operations are given as follows:

ADT specification for stacks:

Value definition: A stack can contain anything of the type its implementing data structure
is defined, i.e. integers, characters, complex records etc.

Definition clause: A stack as explained is a list of elements in which the item added most
recently is taken out first, i.e. the Last item In is the First one Out. Therefore, a stack
can be defined as a LIFO list of elements.

Operations:

(1) create

Function : initializes stack to an empty state.


Precondition : none.
Postcondition : stack is created and is empty.

(2) push

Function : adds new element to the top of the stack.


Precondition : stack is created and is not full.
Postcondition : original stack plus new element added on top.

(3) pop

Function : removes top element from the stack.


Precondition : stack is created and is not empty.
Postcondition : original stack with top element removed.

Chapter 3
72 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

(4) empty

Function : tests whether stack is empty.


Precondition : stack is created.
Postcondition : answer as yes or no depending on the status of the stack;
no change in stack contents.

(5) full

Function : tests whether stack is full.


Precondition : stack is created.
Postcondition : answer as yes or no depending on the status of the stack; no
change in stack contents.

(6) destroy

Function : removes all elements from stack, leaving the stack empty.
Precondition : stack is created.
Postcondition : stack is empty.

These are the ADT specifications for some of the operations, which are commonly
performed on stacks. Reader can think of more such operations depending on a particular
situation and requirement and can write ADT for them on the same lines.

3.3 Implementation
A stack can be implemented using both static and dynamic implementations, i.e. the
space can be allocated at compile time itself or at the execution time of the program.
Each implementation has its own advantages and disadvantages, which we will consider
later.

3.3.1 Implementing a stack using an array


Since all elements of the stack are of the same type, an array can be used to contain them.
We can store elements in sequential slots in the array, placing the first element pushed in
the first array position, the second element in the second array position and so on.
We also need to know how to find the top element when we want to pop and where to put
the new element when we push. Although, we can access any element of an array
directly, we have to confirm to the stack restriction of “LIFO”. So, we will access the
stack elements only through the top, not through the bottom or through the middle.

Therefore, even though the representation of the stack may be a random-access structure
such as an array, the stack itself as a logical entity is not randomly accessed. We can use
its top element only. In the array representation, a variable ‘top’ keeps track of the top
position of the stack. An empty stack is signaled by stack top being zero and a full stack
by top greater than the last storage location.

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 73
Stacks And Queues

In the following programs, stack is an array of size ‘MAX’ and top is a variable, which
keeps track of top position of the stack. Before writing the actual code, let us try and
write an algorithm for it.

Algorithm.

Step 1. Start.

Step 2. Declare the stack of fixed size.

Step 3. Ask the user for a choice, i.e. whether he wants to push an element, pop an
element or print the existing stack.

Step 4. If the choice is push,


1. Check if the stack is full.
2. If the stack is not full, accept an item and insert it on the top of the stack.

Step 5. If the choice is pop,


1. Check if the stack is empty.
2. If the stack is not empty, pop the topmost item from the stack.

Step 6. If the choice is print, print the contents of the existing stack.

Step 7. Ask the user whether he wants to continue or not.


1. If the answer is yes, continue from step 3.
2. If the answer is no, exit.

Step 8. End.

Program: To implement a stack using arrays.

/* Program to show push and pop operations using arrays*/


#include<stdio.h>
#include<stdlib.h>
#define MAX 10 /*declare stack size*/
int stack[MAX],top=0;
main() /*main function starts here*/
{
int ch;
int flag=1;
while (flag==1)
{
system("clear");
printf("\n 1. push.");
printf("\n 2. pop.");
printf("\n 3. print.");
printf("\n");

Chapter 3
74 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

printf("choice:"); /*accepting a choice*/


scanf("%d",&ch);
fflush(stdin);
switch(ch)
{
case 1:push(); /*calling push function*/
printf("\n do you want to continue(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
case 2:pop(); /*calling pop function*/
printf("\n do you want to continue(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
case 3:print(); /*calling print function*/
printf("\n do you want to continue(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
} /*end of switch*/
} /*end of while*/
printf("\nBYE");
} /*main ends here*/

push() /*push function starts here*/


{
int item;
if(top==MAX) /*checking if stack is full*/
{
printf("\nstack is full.");
}
else /*if the stack is not full*/
{
printf("\n enter the item:"); /*accepting the new element*/
scanf("%d",&item);
fflush(stdin);
stack[top]=item;
top++; /*incrementing the top*/
}
} /*push function ends here*/
pop() /*pop function starts here*/
{
int item;
if(top==0) /*checking if stack is empty*/
{
printf("\n stack is empty.");
}
else /*if the stack is not empty*/
{
item=stack[top-1];

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 75
Stacks And Queues

printf("\n%d",item); /*printing the popped element*/


top--; /*decrementing the top*/
}
} /*pop function ends here*/
print() /*print function starts here*/
{
int i;
if(top==0) /*checking if stack is empty*/
{
printf("\n stack is empty.");
}
else
{
printf("\n the existing stack is :");
i=top-1;
while(i>-1) /*printing the stack contents*/
{
printf("\n");
printf("%d",stack[i]);
i--;
}
}
} /*print function ends here*/

3.3.2 Implementing stacks using linked lists

As we know, the linked lists use the concept of dynamic memory allocation, i.e. memory
is allocated as and when needed. Unlike the array version, this implementation has no
program imposed maximum stack size. Nodes are allocated dynamically, using the
malloc() function , as and when needed. If the call to malloc() fails, then it returns
NULL and it is assumed that memory is full. In case of successful memory allocation, the
new structure is logically added. An empty stack is represented by stack top (stack
pointer) pointing to NULL. Before writing the actual code, let us write an algorithm for the
program.

Chapter 3
76 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

Algorithm.

Step 1. Start.

Step 2. Declare the structure of the node for the linked list.

Step 3. Ask the user for a choice, i.e. whether he wants to push an element, pop an
element or print the existing stack.

Step 4. If the choice is push,


1. Allocate space for the new node.
2. Accept the value for the new node.
3. Perform pointer manipulations.

Step 5. If the choice is pop,


1. Check if stack is empty.
2. If the stack is not empty, delete the last node of the linked list and print the
value.
3. Release the space that is not needed now.

Step 6. If the choice is print, print all the nodes of the existing linked list.

Step 7. Ask the user whether he wants to continue or not.


1. If the answer is yes, continue from step 3.
2. If the answer is no, exit.

Step 8. End.

Program: To implementing stacks using linked lists.

/* Program to show push and pop operations using linked lists*/


#include<stdio.h>
#include<stdlib.h>
struct stack
{
int item; /*item field to store the data*/
struct stack *next; /*pointer to successor on stack*/
};
typedef struct stack node;
node *start,*temp;
main() /*main function starts here*/
{
int flag=1;
int ch;
while (flag==1)
{
system("clear");
printf("\n 1. push.");

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 77
Stacks And Queues

printf("\n 2. pop.");
printf("\n 3. print.");
printf("\n");
printf("choice:"); /*accepting the choice*/
scanf("%d",&ch);
fflush(stdin);
switch(ch)
{
case 1:push(); /*calling function push()*/
printf("\n do you want to continue(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
case 2:pop(); /*calling function pop()*/

printf("\n do you want to continue(yes=1,no=0):");


scanf("%d",&flag);
fflush(stdin);
break;
case 3:print(); /*calling function print()*/
printf("\n do you want to continue(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
}
}
printf("\nBYE");
} /*main ends here*/

push() /*push function starts here*/


{
temp=(node *)malloc(sizeof(node));/*allocating new node*/
if(temp==NULL)
{ /*handling memory exceptions*/
printf("\nmemory is full.");
printf("\n");
}
else /*if space is successfully
allocated*/
{
printf("\n enter the item:"); /*accepting a new item*/
scanf("%d",&temp->item);
fflush(stdin);
temp->next=start; /*performing pointer manipulations*/
start=temp;
}
} /*push function ends here*/
pop() /*pop function starts here*/
{
if(start==NULL) /*if the stack is empty*/
{
printf("\n stack is empty.");
}
else /*if the stack is not empty*/

Chapter 3
78 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

{
temp=start;
start=start->next;
printf("\n%d",temp->item); /*printing the popped element*/
free(temp); /*releasing unrequired space*/
}
} /*pop function ends here*/
print() /*print function starts here*/
{
if(start==NULL) /*if the stack is empty*/
{
printf("\n stack is empty.");
}
else
{
printf("\n the existing stack is :"); /*printing the existing
stack*/
temp=start;
while(temp!=NULL)
{
printf("\n");
printf("%d",temp->item);
temp=temp->next;
} /*print function ends here*/
}
}

3.4 Analysis of Stack Implementations

As stated in earlier chapters, an array variable of MAX stack size will take the same
amount of memory, no matter how many array slots are actually used. Therefore, we
need to reserve space for the maximum possible. If more elements need to be stored, then
we may fall short of memory. Also, if elements stored are very less, we may have a lot of
unused space. On the other hand, the linked implementation using dynamically allocated
storage space only requires space for the number of elements actually present in the stack
at run time. But the elements are larger since we must store the link (the next field) along
with the user’s data. Apart from the space requirement, the two implementations can be
compared on other criteria also. For example, programming efforts and program
complexity.
We can compare the efficiency of the two representations with respect to each other in
terms of Big Oh notation.
(1) create operation: In both implementations, operations like creating a stack have
measure O(1). In an array implementation, only the stack has to be declared using
arrays. Also, in the linked implementation, only the memory for the first node has to be
allocated. Therefore, a constant amount of work is involved at all times.
(2) empty or full operation: In both implementations, operations like checking whether
a stack is full or empty have Big Oh measure O(1) because the algorithm has to check for
the presence of just one element.
(3) push or pop operation: In push or pop operations, the number of elements in the stack

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 79
Stacks And Queues

do not affect the amount of work done by these operations. Because, in both operations
we directly access the top of the stack, i.e. only one element. Therefore, push and pop
have measure O(1).
(4) destroy operation: Probably, this is the only operation amongst the basic ones, which
differs from one implementation to other. In the array version, we just have to set the top
field to zero, so it is an O(1) operation. But, in the linked version, we must process every
node in the stack to free the node space. Therefore, the operation is O(n) where n is the
number of nodes in the stack.
In all, the two implementations are almost equivalent in terms of amount of work they do.
Since the destroying operation is not widely used, the difference is not significant.
The Table 3.1 summarizes the Big Oh measures of various operations on the two
implementations.

Operations Array Linked


Implementation Implementation

create O(1) O(1)

empty O(1) O(1)

full O(1) O(1)

push O(1) O(1)

pop O(1) O(1)

destroy O(1) O(n)

Table 3.1
Big Oh measure of common stack operations
The decision to use one of the two implementations depends on the situation. Linked
implementation is more flexible and is preferable where the number of stack elements
vary greatly. It wastes less space when the stack is small. When stack size is
unpredictable, linked implementation is preferable. Array implementation is short, simple
and efficient. When we are sure that we will not need to exceed the declared stack size,
the array implementation is a good choice.

For example, if a customer database for a bank is to be maintained, then the linked
implementation would be preferable because the number of customers is expected to vary
greatly. On the contrary, if a fixed list of students of a class is to be maintained, array
implementation would be more convenient.

3.5 Examples

A stack is an appropriate data structure when information must be saved and then later
retrieved in reverse order. Any situation requiring to store a previous step and coming

Chapter 3
80 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

back to it in future may be a good one to use a stack. Following are some examples using
stack as their data structure.

(1) Reversing an input text line

Brief: As a simple example of using stacks, let us try to make a function that will read a
line of input and will then write it out backward. We can accomplish this task by pushing
each character onto the stack as it is read. When we come to end of the input, we will pop
characters off the stack and they will come off in the reverse order.

Program: To reverse an input text line.

#include<stdio.h>
#include<stdlib.h>
#define MAX 10 /*defining stack size*/
main() /*main starts here*/
{
int top=0;
char stack[MAX],c; /*declaring a character stack*/
system("clear");
printf("\nenter the sequence of characters:");
while((c=getchar())!='\n') /*accepting the text*/
{
stack[top]=c;
top++;
}
printf("\n the reversed string is:"); /*printing the text in reverse
order*/
while(top!=0)
{
printf("%c",stack[top-1]);
top--;
}
} /*main ends here*/

(2) Validating an expression by parenthesis matching

Brief: Consider a mathematical expression that includes several sets of nested


parentheses, for example :
(a-((b+c(d))))

We want to make sure that the parentheses are nested correctly, i.e.

1. We want to check that there are equal numbers of right and left parentheses.
2. Every right parenthesis is preceded by a matching left parenthesis.

Expressions such as

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 81
Stacks And Queues

((a+b)

violate condition 1, and expressions such as-


)a+b(-c

violate condition 2.

Before writing the actual code for the program let us write an algorithm for it and try to
understand the logic.

Algorithm.

Step 1. Start.

Step 2. Declare a character array to store opening braces.

Step 3. Start accepting the expression.

Step 4. If the character is an opening brace, example ‘(‘ or ‘{‘ or’[‘, push it onto the
stack. If successive opening braces, keep pushing them on the stack.

Step 5. If the character is a closing brace, example ‘)’ or’}’ or’]’:

1. Check if the stack is empty.


2. If the stack is empty, it means there was no corresponding opening brace for
the closing brace. Therefore, the expression is invalid.
3. If the stack is not empty, pop an element from the stack,
4. If the popped opening brace corresponds to the closing brace then the
expression is valid.
5. Else the expression is invalid.

Step 6. When we come to the end of accepting the expression:

1. If there are still some opening braces left in the stack, it means that the
expression is invalid.
2. If the stack is empty, expression is valid.

Step 7. End.

Program: To validate an expression by matching left and right parenthesis*/

#include<stdio.h>
#include<stdlib.h>

Chapter 3
82 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

#define MAX 10

char stack[MAX],c,ele;
int top=0;

main() /*main starts here*/


{
int flag=1;
system("clear");
printf("\n enter the expression:"); /*accepting the expression*/
while((c=getchar())!='\n')
{
if(c=='(' || c=='{' || c=='[') /*if the element entered is an
opening brace*/
{
push(); /*push it on the stack*/
}
else
if(c==')' || c==']' || c=='}') /*if the element entered is a
closing brace*/
{
if(top==0) /*if the stack is empty*/
{
flag=0;
break;
}
else
{
pop(); /*pop an element from the stack*/
if((ele=='(' && c==')') || (ele=='{' && c=='}') || (ele=='[' &&
c==']'))
{
/*if corresponding braces are found*/
}
else
{
flag=0;
break;
}
}
}
}
if(stack[0]!=0) /*checking if any brace left in the
stack*/
{
flag=0;
}
if(flag==1)
printf("\n expression is valid.");
else if (flag==0)
printf("\n expression is invalid.");

} /*main ends here*/


push() /*push funtion*/
{
stack[top]=c;
top++;
}

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 83
Stacks And Queues

pop() /*pop function*/


{
ele=stack[top-1];
stack[top-1]=0;
top--;
}

We have tried to keep the above program as simple as possible, because our aim was to
illustrate the concept of stacks and not of making an extensive expression evaluator. This
is why we have made some assumption, which is as follows:
Any expression is to be contained in brackets, for example the following expression will
not work with the above program:
a+(b+c)-d

Rather, it has to be in the following format:

(a+(b+c)-d)

The reason for using a stack in this problem should be clear. The last parenthesis to be
opened should be the first one to be closed. This is simulated by a stack in which the last
element to arrive is the first to leave. Each element on the stack represents a parenthesis
that has been opened but has not yet been closed. Pushing an item onto the stack
corresponds to an opening brace and popping an item from the stack corresponds to
closing a parenthesis.

(
{ {

{-------- {a+(---

{a+(b-c) {a+(b-c)}

Fig.3.2

Chapter 3
84 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

The parentheses stack at different stages of processing

The fig. 3.2 depicts the contents of the stack at various stages of processing the for
expression:
{a+(b-c)}

(3) Postfix expression evaluation

Brief: The sum of 2 and 3 is represented normally as 2+3. This is called infix notation.
The same sum can be represented as +23,which is called prefix notation, and 23+, which
is called postfix notation.

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 85
Stacks And Queues

The prefixes “in”,”pre” and”post” refer to the relative position of the operator with
respect to the two operands. In prefix notation, operator is before the two operands. In
infix notation, operator is in between the two operands. In postfix notation, operator
comes immediately after the two operands. Reader should gather more information on
various notations in relevant literature.

Postfix notation has some obvious advantages over the most commonly used infix
notation.

(1) Need for parenthesis is eliminated.


(2) Knowledge of operator precedence is not required.

We can try to develop a program for evaluating a postfix expression. Each operator
encountered refers to the previous two operands. Each time we come across an operand
we push it on to a stack. When we reach an operator, its operands will be the two top
elements on the stack. We can pop these two elements, perform the operation on them
and push back the result on to the stack. It is then available for use with the next operator.
The following program evaluates a postfix expression using this method. But let us write
an algorithm first.

Algorithm.

Step 1. Start.

Step 2. Declare a stack for storing operands.

Step 3. Start accepting the expression in postfix form.

Step 4. If the character is a digit,


1. Change it to integer format.
2. Push it on the stack. Before pushing, check if stack is full or not.

Step 5. If the character is an operator, pop 2 elements from the stack. These are the
operands on which the operator has to operate. Before popping, check if stack is empty or
not.

Step 6. Compute the result.

Step 7. Push the result back on the stack.

Step 8. Print the result.

Step 9. End.

Chapter 3
86 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

Program: To evaluate a postfix expression.

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define MAX 10 /*declaring the stack size*/
int stack[MAX],top=0;
main() /*main starts here*/
{
int result,operand1,operand2;
char c,item;
system("clear");
printf("\nenter the expression:"); /*accepting the expression */
while((c=getchar())!='\n')
{
if(isdigit(c)!=0) /*if the character entered is a digit*/
{
push(c-48); /*converting character to integer and pushing it
onto the stack*/
}
else /*if the character entered is an operator*/
{
operand2=pop(); /*popping operands from the stack*/
operand1=pop();

switch(c)
{
case '+':result=(operand1 + operand2);
push(result); /*performing operations on the operands*/
break; /*and pushing the result back on stack*/
case '-':result=(operand1 - operand2);
push(result);
break;
case '*':result=(operand1 * operand2);
push(result);
break;
case '/':result=(operand1 / operand2);
push(result);
break;
}
}

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 87
Stacks And Queues

}
printf("\nthe result is %d",result); /*printing the result*/
} /*main ends here*/
push(int temp) /*push function starts here*/
{
if(top==MAX) /*checking if stack is full*/
{
printf("\n stack full.");
}
else
{
stack[top]=temp; /*pushing an operand on the stack*/
top++;
}
} /*push function ends here*/

int pop() /*pop function starts here*/


{
int local;
if(top==0) /*checking if stack is empty*/
{
printf("\n stack empty.");
}
else /*popping an operand from the stack*/
{
local=stack[top-1];
top--;
return(local);
}
} /*pop function ends here*/

Sample Output.

Enter the expression: 49*5+

The result is 41.

(4) Stack for Subprograms

This is one of the most important applications of stacks. What happens within the
computer when subprograms are called? The system (or the program) must remember the
place where the call was made, so that it can return there after the subprogram is
complete. It must also remember all the local variables, CPU registers, and other data, so
that information is not lost while the subprogram is working. We can think of all this
information as one large structure, a temporary storage area for each subprogram.
Suppose that we have 3 subprograms called A, B, and C, and suppose that A invokes B
and B invokes C. Then B has not completed its work until C has finished and returned.
Similarly, A is the first to start work, but it is the last to be finished, not until after B has
finished and returned. Thus the sequence in which this activity proceeds is summed up as
the property last in, first out. If we consider the machine’s task of assigning temporary

Chapter 3
88 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

storage areas for use by subprograms, then those areas would be allocated in a list with
this same property, that is, in a stack.

The example is represented in the figure 3.3.

B
B B

A A
A A A

Fig. 3.3
Stack for subprograms at various stages.

3.6 ADT of Queues

A queue is an ordered collection of items from which items can be deleted from one end
(called the front of the queue) and into which items can be inserted at one end only
(called the rear of the queue). As opposed to stacks, queues are FIFO lists. The element
that was the First to be In, will be the First to be Out. Put in other words, the element
that has spent the longest time in the queue will be the first to be taken out. This is
opposite to a stack, in which we know that the element that has spent the least time is the
first to be out, i.e. LIFO.

There are various examples of queues in the real world. A line at a railway counter or a
bus stop is familiar examples of queues. The person first in the queue will be the first to
get the ticket. Similarly, any new passenger will have to stand at the back of the queue.

To add elements to a queue we access the rear of the queue. To remove elements we
access the front. The middle elements are logically inaccessible, even if we physically
store the queue elements in a random access structure such as an array. The essential
property of the queue is its FIFO access.

As it is clear by now, there are 2 operations that can be applied to a queue. First, new
elements are added to the rear of the queue. We will call this operation enterq. We can
also take the elements off the front of the queue. We will call this operation exitq.

We are also required to check whether the queue contains anything or is empty.
Theoretically, we can always enter in a queue, for in principle, a queue is not limited in
size. But certain implementation, for example an array implementation, requires us to
check whether the data structure is full, before entering a new element. Therefore, we can
also have an operation for this purpose. Before doing anything, we also need to create a
queue and initialize it to an empty state. Also, we might want to delete all elements of the

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 89
Stacks And Queues

queue, leaving an empty structure.

Following is the ADT representation of some of the common operations that can be
performed on queues.

Value definition: A queue can contain anything of the type its implementing data
structure is defined, i.e. integers, characters, complex records, etc.

Definition clause: A queue as explained is a list of elements in which the item added first
is taken out first, i.e. the First item In is the First one Out. Therefore, a queue can be
defined as a FIFO list of elements.

Operations:

(1) create

Function : initializes queue to empty state.


Precondition : none.
Postcondition : A queue is created and is empty.

(2) enterq

Function : adds new element at the rear of the queue.


Precondition : queue is created and is not full.
Postcondition : original queue plus new element added at the rear.

(3) exit

Function : removes front element of the queue.


Precondition : queue is created and is not empty.
Postcondition : original queue minus the front element.

(4) empty

Function : checks whether the queue is empty.


Precondition : queue is created .
Postcondition : answers ‘yes’ or ‘no’; original queue unchanged.

Chapter 3
90 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

(5) full

Function : checks whether the queue is full.


Precondition : queue is created .
Postcondition : answers ‘yes’ or ‘no’; original queue unchanged.

Readers can try their own ADT specifications for any other operations that they may
come across with various implementations.

The enterq operation can always be performed, since there is no limit to the number of
elements a queue may contain. So, an overflow situation should never occur. The exit
operation, however, can be applied only if the queue is nonempty. The result of an illegal
attempt to remove an element from an empty data structure is called underflow.

3.7 Queue Implementations

3.7.1 Array Implementation of Queues:

Representation of a queue as arrays is somewhat different than a stack. In addition to a


one-dimensional array, we need 2 variables, front and rear. Front points to the first
element of the queue and rear to the last element of the queue. Thus, front=rear, when
there are no elements in the queue. The initial condition is front=rear=0.

Initial Queue:

front

rear

Queue after inserting two elements:

front

ele 1 ele 2

rear

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 91
Stacks And Queues

Queue after deleting an element:

front

ele 2

rear

Fig 3.4
Various stages in array implementation of queues

A full queue is shown by rear which is equal to the last storage section.
The following program shows insertion and deletion operations on a queue using array.
Before writing the actual code, let us try to write an algorithm for the program.

Algorithm.
Step 1. Start.
Step 2. Define a queue of the required size.
Step 3. Ask for user’s choice, i.e. whether he wants to insert, delete or print the contents
of the queue.
Step 4. If the choice is insert:
1. Check if queue is full.
2. If the queue is not full, accept an element and insert it at the back of the
queue.
Step 5. If the choice is delete:
1. Check if queue is empty.
2. If the queue is not empty, take out the first element and print it.
Step 6. If the choice is print:
1. Check if queue is empty.
2. If the queue is not empty, print the contents of the queue.
Step 7. Ask the user for further continuation of the program:
1. If the answer is yes, continue from step 3.
2. If the answer is no, exit.

Step 8. End.

Chapter 3
92 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

Program: To delete and insert from a queue.

/*this program shows how to insert and delete from a queue*/


#include<stdio.h>
#include<stdlib.h>
#define MAX 5 /*defining maximum queue size*/
int q[MAX],front=0,rear=0,item;
main() /*main starts here*/
{
int flag=1,ch;
while(flag==1)
{
system("clear");
printf("\n\t Activity Chart.");
printf("\n\t 1. Insert.");
printf("\n\t 2. Delete.");
printf("\n\t 3. Print Queue.");
printf("\n\t Choice:");
scanf("%d",&ch);
fflush(stdin);
switch(ch)
{
case 1:insert(); /*calling insert function*/
printf("\n do you want to continue?(yes=1/no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
case 2:delete(); /*calling delete function*/

printf("\n do you want to continue?(yes=1/no=0):");


scanf("%d",&flag);
fflush(stdin);
break;
case 3: print(); /*calling print function*/
printf("\n do you want to continue?(yes=1/no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
}
}
} /*main ends here*/

insert() /*insert function starts here*/


{
if(rear==MAX) /*checking if queue is full*/
printf("\n queue is full.");
else /*if the queue has space for the new
item*/
{

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 93
Stacks And Queues

printf("\nenter the item:");


scanf("%d",&item); /*accepting the item*/
fflush(stdin);
q[rear]=item;
rear++;
}
} /*insert function ends here*/
delete() /*delete function starts here*/
{
int k;
if (front==rear) /*checking if queue is empty*/
printf("\n queue is empty.");
else /*if the queue is not empty*/
{
printf("%d",q[front]);
for(k=1;k<rear;k++)
{
q[k-1]=q[k];
}
rear--;
}
} /*delete function ends here*/
print() /*print function starts here*/
{
int j;
if(front==rear) /*checking if queue is empty*/
printf("\n queue is empty.");
else
for(j=front;j<rear;j++) /*printing the contents of the
queue*/
{
printf("%d ",q[j]);
}
} /*print function ends here*/

Chapter 3
94 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

The above design has a shortcoming. As we enter and delete elements from the queue,
the front and rear locations also shift forward i.e. as we delete the first item from the
queue, the second location becomes the front. Therefore, we loose the first storage
location for future storage. As we continue entering and deleting elements, the total
storage space available goes on decreasing. Since, we are using arrays as our basic data
structure for queues; this can be a serious drawback.

One solution to the above problem can be to shift all remaining elements up every time
we remove an element from the queue. But, this increases the overheads. To understand
this, take a look at the figure 3.5.
Initial Queue:
front

rear

Queue after inserting two elements:

front

ele 1 ele 2

rear

Queue after deleting an element:

front

ele 2

rear

Fig 3.5
Loosing a storage location

As you can see above, after taking out the front element of the queue, our front location
has incremented to the next element. Thus we have lost the first memory location.
Hereafter, we only have 6 locations to store data. Gradually, this space will go on
decreasing.

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 95
Stacks And Queues

One way of rectifying this problem is to shift the rest of the elements of the queue one
space up each time the front element is deleted, as said above. But if a queue is large, this
will require a lot of effort.

The decision to use this design depends on the final use to which the queue will be put. If
the number of elements to be stored in the queue is large, there will be a lot of processing
required to move up all the elements. On the other hand, if the queue generally contains
only a few elements, this movement may not be much of an overhead. Thus, the complete
evaluation of the design depends on the intended use of the program. We will see other
implementations to rectify this shortcoming as we proceed.

3.7.2 Linked Implementation of Queues

Unlike the array implementation, this version has no program imposed maximum queue
size. Nodes are allocated dynamically using malloc( ) function, as and when required. If
the call to malloc fails, then it returns NULL and is assumed that memory is full. In case
of successful allocation, the new structure is logically added.

To remove a node from a linked list, the node being pointed by the front pointer is
removed and its next node becomes the front node. Take a look at the following
diagrams.

Existing Queue.

start 1 2 NULL

Inserting another node at the rear.

1 2 3
start NULL

Deleting a node from the front.

2 3
Start NULL

Fig 3.6
Linked implementation of Queues

The following program shows how to use linked lists to implement queues. Before
writing the actual code, let us write an algorithm for the program.

Chapter 3
96 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

Algorithm.

Step 1. Start.

Step 2. Declare the structure of the node for the linked list.

Step 3. Ask for user’s choice, i.e. whether he wants to insert, delete or print the contents
of the queue.

Step 4. If the choice is insert:

1. Allocate space for the new node.


2. Accept a value for the node.
3. Perform pointer manipulations.

Step 5. If the choice is delete, delete the first node of the linked list and print the value.

Step 6. If the choice is print, print the contents of the existing queue.

Step 7. Ask the user for further continuation of the program:


1. If the answer is yes, continue from step 3.
2. If the answer is no, exit.

Step 8. End.

Program: To implement queues using linked lists.

/*this program uses linked lists to implement queues*/


#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
struct queue /*defining structure for the node*/
{
int item;
struct queue *next;
};
typedef struct queue node;
node *start,*temp,*local;

main() /*main starts here*/


{
int flag=1;
int ch;
start=(node *)malloc(sizeof(node));
local=start;

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 97
Stacks And Queues

while(flag==1)
{
system("clear");
printf("\n");
printf("\n\t Activity Chart.");
printf("\n\t1. Insert.");
printf("\n\t2. Delete.");
printf("\n\t3. Print.");
printf("\n\t Choice:");
scanf("%d",&ch);
fflush(stdin);
switch(ch)
{
case 1:insert(); /*calling insert function*/
printf("\n do you want to continue:(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
case 2:delete(); /*calling delete function*/
printf("\n do you want to continue:(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;
case 3:print(); /*calling print function*/

printf("\n do you want to continue:(yes=1,no=0):");


scanf("%d",&flag);
fflush(stdin);
}

}
} /*main ends here*/

insert() /*insert function starts here*/


{
temp=(node *)malloc(sizeof(node));
printf("\n enter the element:"); /*accepting the element*/
scanf("%d",&temp->item);
fflush(stdin);
local->next=temp; /*performing pointer manipulations*/
temp->next=NULL;

local=temp;
} /*insert function ends here*/

delete() /*delete function starts here*/


{
if(start==local)
{
printf(“\n queue is empty.”);
}
else
{

Chapter 3
98 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

start=start->next;
printf("%d",start->item); /*printing the element to be
deleted*/
}
} /*delete function ends here*/
print() /*print function starts here*/
{
node *loc;
loc=start->next;
if(start==local)
{
printf(“\n queue is empty.”);
}
else
{
printf("\n the existing queue is:\n"); /*printing the contents of the
queue*/
for(;loc!=NULL;loc=loc->next)
{
printf("%d ",loc->item);
}
}
} /*print function ends here*/

3.8 Analysis of Queue Implementations

An array of MAX queue size will take same amount of memory, no matter how many
array slots are actually used. The linked implementation using dynamically allocated
storage space only requires space for the number of elements actually in the queue at the
run time, plus space for the external pointers. However, the node elements are larger,
since we must store the link as well as the user data.

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 99
Stacks And Queues

We can also compare the relative “efficiency” of the two implementations, in terms of
Big Oh. Following are the Big Oh measurements of some of the common operations that
are performed on queues.

(1) create: In both implementations, create operation has a measure of O(1). It takes
fixed amount of work in any case.

(2) empty and full: In both implementations, these two operations have measure O(1)
only. Because, the algorithm has to do only one operation, that of checking whether the
queue contains anything or not.

(3) enterq and exitq: These operations are also O(1) in both implementations. The
number of elements in the queue does not affect the work done by these two operations.
In both implementations, we can directly access the front and rear of the queue.
Therefore, amount of work done by these two operations is independent of queue size.

(4) deleting the entire queue: This operation differs from one implementation to
other. The array implementation just sets the front and rear indexes, so it is an O(1)
operation. The linked implementation has to access each node and free it explicitly.
Therefore, this operation has the measure O(n), where n is the number of elements in the
queue at that time.
As with the array and linked implementation of stacks, these two implementations of
queues are more or less equivalent in terms of amount of work they do, possibly differing
in one operation. Following table summarizes the Big Oh measures of various operations
on the two implementations of queues.

Operations Array Linked


Implementation Implementation

create O(1) O(1)

empty O(1) O(1)

full O(1) O(1)

enterq O(1) O(1)

exitq O(1) O(1)

destroy O(1) O(n)

Table 3.2
Big Oh comparison of queue operations

The answer to the question, which implementation is better, depends on the requirements
of your application.

Chapter 3
100 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

3.9 Other type of Queues


(A) Circular Queue:
As we know, in linear (array implementation) queues, both the front and rear are
increased and never decreased i.e. as the queue moves down the array, the storage space
at the beginning of the array is discarded and is never used again. One solution for this
problem as we saw is the use of linked lists. Another way to overcome this inefficient use
of space is to consider arrays as a circular structure rather than a linear structure. In this
way, as items are added and deleted from the queue, the front will continuously chase the
rear around the array till overflow condition i.e. the queue is full.
In such a circular queue, the rear/front pointers are reset to point to the first position after
reaching the highest numbered location.

Circular Queue Representation:

rear

front

Fig. 3.7
A circular queue

Before proceeding to write formal programs, let us decide the conditions for empty queue
and full queue. Consider the queue shown in the figure 3.8.
front

(1) empty queue

rear
front

Item 1
(2) queue with
one item

rear

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 101
Stacks And Queues

front

Item 1 item 2
(3) queue with one
empty position

rear
front

Item 1 item 2 item 3


(4) full queue

rear

Fig.3.8
Various situations in a circular queue

Note: In the figure 3.8 circular arrays are drawn as linear arrays but treatment will be
different.

As the figure 3.8 indicates, the front and rear indices are at same positions for empty
queue and full queue. To differentiate between the two, we introduce a new variable
called counter, to hold the number of elements in the queue. The value of counter is
increased when an element is added and decreased when an element is deleted. If counter
is equal to zero, it indicates that queue is empty. If counter is equal to MAX then it
indicates that queue is full.

Following program implements circular queue with the help of a counter.

Program: To implement a circular queue.

/*This program implements circular queues with a counter*/


#include<stdio.h>
#include<stdlib.h>
#define MAX 5 /*defining maximum queue size*/
int i,loc;
int cq[MAX],front=0,count=0,rear=-1;
main() /*main starts here*/
{

Chapter 3
102 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

int flag=1, ch;


while(flag==1)
{
system("clear");
printf("\n");
printf("\n\t Activity Chart.");
printf("\n\t1. Insert.");
printf("\n\t2. Delete.");
printf("\n\t3. Print.");
printf("\n\t Choice:");
scanf("%d",&ch);
fflush(stdin);
switch(ch)
{
case 1:insert(); /*calling insert function*/

printf("\n do you want to continue:(yes=1,no=0):");


scanf("%d",&flag);
fflush(stdin);
break;
case 2:delete(); /*calling delete function*/
printf("\n do you want to continue:(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
break;

case 3:print(); /*calling print function*/


printf("\n do you want to continue:(yes=1,no=0):");
scanf("%d",&flag);
fflush(stdin);
}

}
} /*main ends here*/
insert() /*insert function starts here*/
{
if (count==MAX) /*checking if queue is full*/
{
printf("\nQueue is full.");
}
else /*if the queue is not full*/
{
rear++;
if(rear==MAX)
rear=0; /*making rear point to front*/
printf("\nenter the element:"); /*accepting the element*/
scanf("%d",&cq[rear]);
fflush(stdin);
count++;
}
} /*insert function ends here*/
delete() /*delete function starts here*/
{
if(count==0) /*checking if queue is empty*/

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 103
Stacks And Queues

{
printf("\n queue is empty.");
}
else /*if the queue is not empty*/
{
printf("%d",cq[front]); /*printing and deleting the element*/
front++;
if(front==MAX)
front=0;
count--;
}
} /*delete function ends here*/
print() /*print function starts here*/
{
if(count==0) /*checking if queue is empty*/
{
printf("\n queue is empty.");
}
else
{
for(i=front,loc=0;loc<count;i++,loc++)
{
if(i==MAX)
i=0;
printf("%d ",cq[i]); /*printing the contents of the
queue*/
}
} /*print function ends here*/
}

(B) Priority Queue


Stacks and Queues are data structures whose elements are ordered according to the
sequence in which they were inserted. The pop operation gets the last element inserted
and the exitq operation gets the first element inserted. Any intrinsic order (alphabetic or
numeric), is ignored in the stack or queue operations.

Chapter 3
104 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

As opposed to stacks and queues, priority queues are data structures in which the
outcome of basic operations depends on the intrinsic ordering of elements. There are two
types of priority queues:

(1) Ascending priority queue.


(2) Descending priority queue.

An ascending priority queue is a collection of items into which items can be inserted
arbitrarily and from which only the smallest item can be removed. A descending priority
queue is similar but allows deletion of only the largest item.

The elements of a priority queue need not be numbers or characters that can be compared
directly. They may be complex structures that are ordered on one or several fields.
Sometimes, the field on which the elements of a priority queue are ordered is not even
part of the elements. It may be a special external value used solely for ordering a priority
queue, for example time of insertion.

Reader can try and develop ADT specification for a priority queue.

3.10 Examples

A queue is an appropriate data structure when information must be saved and then later
retrieved in the same order it was entered. In other words, in a queue the element that has
spent the most time is the one to come out first. This is opposite to stacks where the
element that has spent the least time or the element that is the most recent, comes out
first. Following are some examples using queue as their data structure.

(1) Resource Scheduling

Operating system uses queue data structure in various ways to schedule various computer
resources like the CPU (Central Processing Unit). When we ask the computer to run a
particular program on a multiuser system, the operating system adds our request to its job
queue. When the request gets to the front of the queue, the operating system allocates
other resources to it and executes the requested program. Similarly, queues are used to
allocate various peripheral devices like printers, disks and tapes to user requests. The
Operating system maintains queues of requests to print, read, or write to each of these
devices.

(2) Simulation

One of the most important applications of queues is simulation. A simulation program


attempts to model a real-world situation, when actually performing it may be dangerous
or extremely costly. Each object and action in the real situation has its counterpart in the
program. A good simulation should produce results, which mirror the results of actual
situation.

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 105
Stacks And Queues

3.11 Application

So far we have seen various situations in which stacks and queues are used as appropriate
data structures. Converting one type of expression into some other type is another such
major situation where stacks and queues are used effectively.

Various mathematical applications require conversion of infix expressions into postfix


expressions to avoid the use of braces because infix expressions require additional space
to store braces alongwith operators and operands. With postfix expressions the need to
store braces is eliminated. Consider the following infix expression:
(a+b)

As we know in a postfix expression the operator comes immediately after the two
operands on which it has to act. Therefore, on converting the above infix expression to a
postfix expression, we will get:

(ab+)

As we see the need to maintain braces is eliminated. Now, let us consider the various
activities involved in achieving the result.

Step 1: Our program starts with accepting an infix expression as a string in a character
array c[].

Step 2: As long as the array element is not the end of string character ‘\0’, look for
closing braces ‘)’. Until the closing brace is not found, check if the character is alphabet.
If it is an alphabet insert it into a circular queue queue[], using the function insertq( ).
The reason to use a circular queue should be clear. If the character is not an alphabet, i.e.
it is an opening brace ‘(‘ or an operator, push it onto a stack stack[] using the function
push( ).

Try to understand, why we have used a stack to store opening braces and operators and a
queue to store operands. Remember, whenever we come across a closing brace ‘)’, we
need to search for its immediate opening brace counterpart, which was the last one to be
encountered as well as the operator which was encountered in between those two.
Clearly, this is a LIFO situation. Therefore, a stack is required to store braces.

Now, remember the example in which we converted (a+b) to ab+. Note that the first
operand ‘a’ came first in the final result. Also, the order of ‘a’ and ‘b’ was the same i.e.
they were printed in the same order in which they were encountered. This pattern remains
same, however big the infix expression may be. Clearly, this is a FIFO situation.
Therefore, a queue is an obvious choice.

Step 3: If a closing brace is encountered, take out all elements existing in the queue at
that point of time using function deleteq () and pop all operators from the stack using
function pop() until the first opening brace is encountered.

Chapter 3
106 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

Program: To convert an infix expression to a postfix expression.


/*This program converts an infix exp. to postfix exp.*/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define MAX 10

char stack[MAX],queue[MAX],item;int top=0;


int front=0,count=0,rear=-1,i=0;
char c[20];
char pop();
main()
{

system("clear");
printf("\n enter the infix expression:");
scanf("%s",c);
printf("%s",c);

while(c[i] !='\0')
{
if(c[i]!=')')
{
if(isalpha(c[i])!=0)
{
insertq();
}
else
{
push();
}
}
else
{
while(count!=0)
{
deleteq();

}
while(item!='(')
{
item=pop();

}
item = 'a';

}
i++;
}
}

push()
{
if(top==MAX)
{

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 107
Stacks And Queues

printf("\nstack full.");
}
else
{
stack[top]=c[i];
top++;
}
}

char pop()

{
if(top==0)
{
printf("\nstack empty.");
}
else
{
top--;
if(stack[top]!='(')
printf("%c",stack[top]);

return(stack[top]);
}
}

insertq()
{
if (count==MAX)
{
printf("\n queue is full.");
}
else
{
rear++;
if(rear==MAX)
rear=0;
queue[rear]=c[i];
count++;
}
}

deleteq()
{
if(count==0)
{
printf("\nqueue is empty.");
}
else
{
printf("%c",queue[front]);
front++;
count--;
}
}

Chapter 3
108 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

Output:

Enter the infix expression :


(((a-(b+c))*d)$e+f)abc+-d*ef+$
Assumptions:

1. Whole expression is enclosed in braces.

Example: (a+b) valid expression.

a+b invalid expression.

2. Only simple braces ‘(‘ or ‘)’ are used.

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 109
Stacks And Queues

SELF ASSESSMENT
1. A stack is a __________ list.

2. A queue is a _________ list.

3. _______ is an appropriate data structure when information must be saved and then
later retrieved in reverse order.

4. _________ is an appropriate data structure when information must be saved


and then later retrieved in the same order.

5. The result of an illegal attempt to remove an element from an empty data structure is
called __________.

6. The result of an illegal attempt to add an element into a full data structure is called
__________.

Answer the following in your own words:

1. What is the basic difference between stacks and queues?


2. What is a LIFO list and a FIFO list?
3. What are the various functions that can be performed on stacks and queues?
4. What is a circular queue?
5. What is a priority queue?

Chapter 3
110 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

SUMMARY
Key points covered in this chapter are as follows:

♦ A stack is an ordered list in which all insertions and deletions are done at one end,
called the top.

♦ A queue is an ordered list in which all insertions take place at one end, the rear, while
all deletions take place at the other end, the front.

♦ Unlike an array, the definition of stacks and queues provide for the insertion and
deletion of items. So, stacks and queues are dynamic, constantly changing objects.

♦ Queues provide FIFO storage as opposed to LIFO storage provided by stacks.

♦ A stack is a dynamic structure i.e. it changes as elements are added to and removed
from it. The operation that adds an element to the top of a stack is usually called
PUSH and the operation that takes the top element off the stack is called POP.

♦ Even though the representation of the stack may be a random-access structure such as
an array, the stack itself as a logical entity is not randomly accessed.

♦ Stacks and queues can be implemented using arrays as well as using linked lists. As
stated in earlier chapters, an array variable of MAX stack size will take the same
amount of memory, no matter how many array slots are actually used. Therefore, we
need to reserve space for the maximum possible. On the other hand, the linked
implementation using dynamically allocated storage space only requires space for the
number of elements actually present in the stack at run time. But the elements are
larger since we must store the link (the next field) along with the user’s data.

♦ Stack is an appropriate data structure when information must be saved and then later
retrieved A in reverse order. Any situation requiring to backtrack to some earlier
position may be a good one to use a stack.

♦ There are 2 operations that can be applied to a queue. First, new elements are added
to the rear of the queue. We will call this operation enterq. We can also take the
elements off the front of the queue. We will call this operation exitq.

♦ The result of an illegal attempt to remove an element from an empty data structure is
called underflow.

♦ The result of an illegal attempt to add an element into a full data structure is called
overflow.

♦ As we know, in linear (array implementation) queues, both the front and rear are
increased and never decreased i.e. as the queue moves down the array, the storage

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 111
Stacks And Queues

space at the beginning of the array is discarded and is never used again. One solution
for this problem as we saw is the use of linked lists. Another way to overcome this
inefficient use of space is to consider arrays as a circle rather than a straight line. In
this way, as items are added and deleted from the queue, the front will continuously
chase the rear around he array till overflow condition i.e. the queue is full.

♦ As opposed to stacks and queues, priority queues are data structures in which the
outcome of basic operations depends on the intrinsic ordering of elements. There are
two types of priority queues:

(1) Ascending priority queue.


(2) Descending priority queue.

♦ A queue is an appropriate data structure when information must be saved and then
later retrieved in the same order.

Chapter 3
112 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority
Stacks And Queues

LAB EXERCISE
Stacks.

1. Write a single program,

1. To convert an infix expression to a postfix expression.


2. To evaluate that postfix expression.

2. Write C programs for converting,

1. A prefix string to postfix.


2. A postfix string to prefix.
3. A prefix string to infix.
4. A postfix string to infix.

Queues.

1. Use Queues to simulate a situation of a railway station.

1. Make a queue for keeping the trains waiting to enter the station.
2. Provide unique numbers to trains.
3. Count the number of trains in the queue at a particular time.
4. Search for the train with a particular number.

2. Try to simulate an operating system. Recall that tasks are submitted to the
operating system in a queue. They can be executed in the same order or in the
order of their priority. The task with the highest priority will be the first one to
be executed.
For example, if four programs p1, p2, p3 and p4 are submitted to the operating
system, they will be stored in a queue as follows.

P1 P2 P3 P4
Front end

If the above programs have the priority as follows:

P1 = 3
P2 = 2
P3 = 1
P4 = 4

Chapter 3
Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority. 113
Stacks And Queues

Then the programs are to be executed in the following order:


1. P3
2. P2
3. P1
4. P4

Now, try to implement the above activity by using stacks and queues.

1. Accept a new program into a queue.


2. Ask the user for its priority.
3. Use the stack for storing the programs with the topmost program having the
highest priority.

Chapter 3
114 Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

You might also like