0% found this document useful (0 votes)
18 views22 pages

Unit 13

Uploaded by

jksvsgla
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)
18 views22 pages

Unit 13

Uploaded by

jksvsgla
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/ 22

~taStructures time, but a good executive would presumably manage to get the stack emptied periodically.

It
turns out that sometimes a computer program is naturally organised in this way, postponing
some tasks and doing others. Thus, pushdown stacks appear as the fundamental data structure
for many algorithms. We may draw a stack in any one of the forms as in Fig. I. Each one of the

data I data 1
data I data 1 1
data I data I
data

Fig. 1: Depicting stacks.

above have an open and one closed end. The data movement(i.e. storage and retrieval) takes
place only at the open end, i.e. data is stored and retrieved in last in first out(LIF0) order. We f1

generally use the form given in 1a, having the open end in up direction. We will see a great
many applications of stack in the unit.
ii
The open end of the stack is called the top of the stack. The store and retrieval operations for a
stack are called PUSH and POP, respectively. Fig. 2 shows how a sample stack evolves through
the series of PUSH and POP represented by the sequence:

Each letter in this list means "PUSH(the letter); each asterisk means "POP". A "PUSH
operation on an object places it on the top of the stack while a "POP" operation removes the top
most object on the stack for carrying out some operation or other.

In Fig. 2, there are 16 columns, including the first column as the first column, which contains
the labels of the 4 rows. In first row we have a symbol, a character or an asterisk. In the next 2
rows, we have the action initiated by the symbol, either a PUSH or a POP operation. In the
fourth row, we have the status of the stack after the operation. For example, in the first row the

-
S y m b
PUSH
POP
A
o

A
l
S
A X
A
S A M P
M P L
L
E
E

E
* *

L
*
P M
*
A
*
S
*
I
Fig. 2: An illustration of stack operations.

second column, we have 'A'. Since this pushed A into the stack, we have the character 'A' in the
second row. Nothing has been popped, so the third row is empty. The last row shows the stack
with the character 'A'. In the third column, we have the asterisk in the first row, which indicates
a POP operation. The row corresponding to POP operation has 'A', since 'A' has been popped.
In this last row we have an empty stack since we have popped the only character in the stack.
Now you can study the remaining columns to understand the PUSH and POP operations.

Another fundamental restricted-access data structure is called the Queue. Again, only two basic
L
operations are involved; one can insert an item into the Queue at the beginning and remove an
Ifem from the end. Perhaps our busy executive's 'in' box should operate lik- -
hen work that aJ-rives first would get done first. In a stack, something can g...t:av..,.,,
yueue, s~nce Stacks and Queues
' ~ htn a v ; ~ A at the
bottom, but in a Queue everything is processed in the order received. Queues obey a
First Out(FIF0)'' discipline. We may draw Queue in any one of the forms given in Fig."First
3.
In
:- 9
Queue is marked with two open ends called front and rear. In the next section. we will d i Q r l l c ~
~~-~ ...> .. - ..--. ----"-u I
Rear Front

i-xc--j
data

e?d Front

/ data I data I data


7
rear front front rear
(4 (4
Fig. 3: Depiction of Queue.

implementation of stacks.

13.3 STACK OPERATIONS AND IMPLEMENTATIONS

Basic operations on stack are as follows:


1) Create a stack.
2) Check whether a stack is empty.
3) Check whether a stack is full.
4) Initialise a stack.
5) Push an element onto a stack(if stack is not full).
6 ) Pop an element from a stack(if stack is not empty).
7) Read a stack top.
8) Print the entire stack.
Stack(a special case of list) can be implemented as one of the following data structures:

Array

Linked list

-
13.3.1 Array Implementation
II
The simplest way to represent a stack is by using a one-dimensional array, say s t a c k [ l ] with
roam for N elements, me firs[e\ement
v,~wi\l~stack[l], and SO on. An associated variable
stack la
I
to,, to the top element of fie stack. Type definition for a.sequentially
. 1
I
typedef s t r u c t i i n t
}element; element
. -
s t a c k [ STACK-SIZEm
i n t top = -l;/*I)enOtes du "1p.y ------
to check h e value of top.If it is ~ ~ P L
-. I ,
Structures To check whether the stack is empty, we Just ,+uri~eit returns 1.
;$ah value of top is - 1 and the function returns 0; 0th. -- - -
7 .

i n t st ackempty ()

I else

Given a sequentially allocated stack, and a value to be pushed, thls proceaure maws mt: new rup
of the stack to be that value.

void add ( i n t *top, element item)


<
If (*top >= S T A C L S I Z E M - 1) {

. -- --

El) Write a function POP to pop a stack.

Although this method of allocating storage is adequate for many applications, there are many
other applications where the sequential allocation method is inefficient and therefore not
acceptable.

For such applications, we store a stack element in a structure with a pointer to the next lower
element on the stack.

typedef s t r u c t node {
i n t data;
st r u c t node *next ;
> Item;

Suppose S is a pointer to topmost node in the stack. Here is a function to check if the stack is
empty.

i n t IsEmpty(1tem t S)

i f (S != NULL)
return 0;
else

PUSH, POP and TOP operations involve inserting, deleting and reading item at the top of this
list structure.
. -

I Here is how we cany out the Pop operation


ta Structures

2. ~ p p l ythe operator to the two operands immediately preceding the 0Prator.

3. Replace the operator and the two operands by the answer and continue reading right.
When
. .-- this rule, this is how we will evaluate the expression in eqn. (1) on the
we apply
--

preceding page. The details are in Table. 1.


Table 1: Evaluation of an expression in RPN notation.

1 The next operator is /. Replace - 2 , s and / by -? in the I

How do we convert an expression in infix notation to RPN? Consider the expression


+ +
5 (3 - 5)/(2 3). We first convert the expressions in brackets to reverse polish notation. The
+
expression becomes 5 [3,5,-]/[2: 3, +]. We treat the converted forms in square b r a c u s to be
operands.

There are no more expressions in round brackets to be converted. Now, we apply the priority
rules. / has higher priority than +, +
so the expression becomes 5 [[3,5,-1, [2,3,+], /I. In the
+I.
next step, we convert this to [5,[[3,5,-1, [2,3,+I, /], Now, we write the expression without
square brackets.

Here is an exercise for you.

I E3) Evaluate the expression 5,3,5, -,2,3, +,/, + and check that its value is the same as

I We may write a general algorithm as follows:

I 1)
2)
Initialise the stack to be empty.
For each character in the input string, if it is an operand, append it to the output. If it is an
operator that has higher precedence than the operator on the top of the stack or if the stack
is empty, push it onto the top of the stack. If the incoming operator has the same or lower
precedence than the operator on the stack, pop the stack and append it to the output. Repeat
this process till the operator on the top of the stack has lower precedence than the incoming
operator or the stack is empty. After this, add the incoming operand to the top of the stack.
3) If the input end is encountered, pop the elements in the stack one by one and append them
to the output.
Let us write a C programme that converts an infix expression to RPN. We will put some
restrictions on the infix expression to keep our program simple. We will assume
1; The numbers are single digit numbers and negative integers are not allowed. Stacks and Quet

2. The expression does not contain round brackets; we will do the conversion purely
according to priority. Also, we will assume that the expression does not contain the
division operator I.

Here is the program; this uses the stack functions we defined earlier.
/*Program-13.2. A program t h a t converts an
i n f i x expression t o RPN.
F i l e name: uni t l 3 - i n f i x 2 p o s t f i x . c*/
#include < s t d i o .h>
#include<ctype.h>
#include c s t d l i b . h>
#define MALSTRING 20
typedef s t r u c t node {
int d a t a ;
s t r u c t node * n e x t ;
1 Item;
i n t IsEmpty(1tem * S ) ;
void EmptyStack(1tern ** S ) ;
void Push( int x , Item ** S ) ;
i n t Top(1tem * S ) ;
void Pop(1tem ** S ) ;
void print,stack(Itern * S ) ;
void E r r o r ( c h a r m e s s a g e ) ;
i n t i s h i g h e r ( c h a r o p l , char op2);
i n t main()

Item *S=NULL ;
char c l o p , out[MAX_STRING];
int i=O, j=O;
while((c=getchar()) ! = ' \ n l ) {
i f ( c = = ' ')
continue ;
i f ( i s d i g i t (c))
o u t [i++]=c ;
e l s e i f (IsEmpty(S))
Push(c ,&S) ;
else{
while( !IsEmpty(S) && ishigher(Top(S) , c ) ) (
o u t [i++]=Top(S) ;
Pop(&S) ;
3
Push(c,&S);
3
1
while ( !IsEmpty(S)){
out[i++]=Top(S);
Pop(&S) ;
1
out[i]='\nl;
f o r ( j = 0 ; j <= i-1; j++)
p r i n t f ("%ct',o u t [ j 1 ) ;
return (0) ;
1
Listing 1: A program to convert an infix expression to RPN.

We have used the function i s d i g i t () from the standard C library which is defined in
c t y p e s .h to checks whether the character input is a digit or a non-digit. The only new thing
in the program is the function i s h i g h e r () which checks the priority of the operators and
ta Structures returns 1 or 0 depending on whether the first operator has higher priority than the second
operator or not. We ask you to write such a function in the next exercise.

E4) Write a function ishigher () that checks the priority of operators as described above.

We can also use stacks to evaluate expressions in postfix notation. To do this, when an operand
is encountered, it is pushed onto the stack. When an operator 1s encountered, it is appl~edto the
first two operands that are obtained by popping the stack and the result is pushed onto the stack.
i For example, the postfix expression
i

I 853+9*+4+

ki is evaluated as follows: On reading 8, 5 and 3 the stack contents are as follows:

The remaining steps are shown in Table. 2.


Table 2: Evaluation of an expression in RPN using a stack.

+,
On reading 3 and 5 are popped from the stack
+
and added. The result 8 = 5 3 is pushed onto 1 I
1 Next, 9 is pushed onto the stack 11- 9 I I

On reading *, 8 and 9 are popped and 9 * 8 = 72 is


pushed onto the stack

On finding +,72 and 8 are popped out and 72 +


8 = 80 is pushed onto the stack

I Now 4 is pushed onto the stack //4/1

+
Finally, a is read and 4 and 80 are popped, the
!
1
+

I
result 4 80 is pushed onto the stack.
1
84
I

End of the string is encountered. Therefore, stack is popped and 84 is is the result.
I
E5) Write a function that evaluates an expression in RPN that is given as string. You can make
all the assumptions that we made in the program we wrote for converting an infix
expression to an expression in RPN.
i
-~

While recursive algorithms are elegant, not all programming languages suppo~trecursion. In the Stacks and Queue
next subsection, we will see how to simulate recursion in such languages.

13.4.2 Simulation of Recursion Using Stacks

The discussion in this subsection is based on Section 3.4 of the book Data Structures using C
and C++, Second edition by Y h n g s a m , M. . IAugenstein
. and A. M. Tenenbaum. Recall the
factorial function, that can be defined recursive1y.
1 i n t f a c t ( i n t n)
2 1
3 int x , y ;
4 i f (n == 0)
5 return ( 1 ) ;
6 x = n - 1 ;
7 y = fact(x);
8 r e t u r n (n * y ) ;
9 1
We can write this program in a non-recursive form by simulating this recursive solution using
elementary operations. Why should we simulate recursion?

Many programming languages like FORTRAN, COBOL and the machine languages do not
support recursion. So, in these cases, we can easily find a recursive solution to a problem and
write a non-recursive program for it. Also, sometimes, a recursive solution can be more
expensive in terms of time and space. Often the difference is small and can be ignored because
recursive solutions are logically simple and elegant. However, in some cases where the program
will be run thousands of times, using recurrence may prove to be expensive. However. with
increase in computing power and easy availability of cheap memory, such instances are fewer
than before.

So, when a recursive solution proves to be costly in terms of running time and memory used, the
best alternative for us is to solve a problem using recursion and then convert it into a
non-recursive form. Stacks are useful in this regard. As an example of this procedure, we will
rewrite the above factorial function in non-recursive form.

For this, you may look at the introduction to Unit 8 to recall how function calls work. Let us see
what happens in these steps.

I) Passing arguments: For a parameter of the function, its argument is copied within the data
area of the function and all the changes are made to the local copy. The original data
cannot be altered.
2) Allocating and initialising local variables: These local variables include all those
declared in the function as well as the temporaries that are created during execution. For
example, in a statement such as x=f a c t ( n ) ; a temporary must be created to hold the
value o f f a c t (n) before it is assigned to x.
3) Transferring control to the function: Recall that PC, the Programme Counter holds the
address of the next instruction to be carried out. The function has to return control to this
address when it has finished its job. So, this address, called the return address has to be
stored. After the arguments and return address are passed, the program hands over the
control to the function.
When the function returns control, first the return address is retrieved and stored in a safe place.
After this, the data area of the function, containing all the local variables(inc1uding local copies
of arguments), temporaries and return address, is freed. The control is returns to the program
and it starts execution from the return address. The value returned by the function, if any, is
stored away safely.

Suppose the main function calls a function f l and f l in turn calls another function f2. The
ta Structures situation is as shown in Fig. 4. Here the control is somewhere in f2. Each function has a location
Main Program f1

R
R.eturn Address

for return address. The return address area of f2 has the address of the instruction in fl
immediately following the call to f2. Similarly, fl has the address of the instruction in the main
program immediately following the call to f l . If there are any function calls made by f2, f2
returns the control to fl after all of them have returned the control back to it. Similarly, fl
cannot return control to the main program till control returns to it from f2. So, the series of
return addresses have a natural structure of a stack. At any point, we can only access the return
address from the function that is currently executing.

We will now use a stack to simulate the recursive calls of f a c t . Each item in the stack will
contain the 'return address' of the function call and the temporaries. The item in the stack must
contain X, n and y. The control will return to the function at either to the assignment of f a c t
to y or to the main program f a c t (x). We will have two labels, l a b e l l and l a b e l 2 . Let
l a b e l 2 be the label of a section of a code

label2: y = result;

and let l a b e l 1 be the label of the statement

l a b e l l : return(resu1t) The variable r e s u l t will be used to store the value returned by 1

a call of the f a c t function. We will store the return address in an integer i which will be either
1 or 2. We use the switch () statement
I
switch (i){
case 1:
goto l a b e l l ;
case 2:

for returning from a recursive call. The data area stack for this example is as follows:
# d e f i n e MAXSTACK 50
struct dataarea

I i n t param,
int x;
long i n t y;
short i n t r e t a d d r :

I s t r u c t stack{
i n t tmp
s t r u c t d a t a r a r e a item[MAXSTACK]
i

I i
We use param in the data area to store the different parameter values with the simulated
function is called. We also declare a current data area to hold the values of the variables in the
simulated "current" call on the recursive function. The declaration is:
struct dataarea currarea; i
In addition, we declare a single variable result by I
long int r e s u l t ; Stacks and Queues

This variable is used to communicate the returned value of the f a c t from one recursive call of
fact to the outside calling function. Since the elements on the stack of data areas are structures
and it is more efficient to pass structures by reference, we do not use a function pop to pop a
data area from the stack. Instead, we write a function popsub defined by
void popsub(struct stack *ps, st ruct datarea *pares)

The call popsub (&s ,&area)pops the stack and sets area to the popped element.

A return from fact is simulated b) the code.


r e s u l t = value t o be returned;
i = currarea.retaddr;
popsub(&s, &cumarea);
switch (i){
case 1 : goto l a b e l l ;
case 2: goto l a b e l 2 ;
I
To simulate a recursive call on fact we push the current data area on the stack, reinitialise the
variables currarea. param and currarea. retaddr to the parameter and return address
of this call, I-espectivelyand then transfer the control to the stait of the simulated routine. Note
that currarea. x holds the value of n - 1 which will be the new parameter. On recursive call,
we wish to eventually return to label2. The code to accomplish this is
push(&s, &cumarea);
currarea.param= currarea.x;
currarea. retaddr =2 ;
goto s t a r t ;
/* s t a r t i s the label of the start of
the simulated routine;$/

Of course, we have to write the pobsub and push routines in such a way that they pop and push
entire structures of type dataarea rather than sirnple variables. Another constraint arising from
the array implementation of stacks is that variables currarea. y must be initialised to some
I
value or an error will result in the push routine on assignment of currarea.y to the corresponding
I
field the top data area when the program starts.
I

t When the simulation first begins. we initialise the current area so that currarea. param
i
equals n and currarea. retaddr equals ](indicating a return to the calling routine). We
I
must push a dummy data area onto the stack so that when popsub is executed in returning to the
main routine, an underflow does not occur. We should also initialise this duminy data area so as

i
not to cause an error in the push routine. Thus, the simulated version of the recursive fact
routine is as follows:
struct dataarea{
in t param;
int x ;
long int p;
short int retaddr;

struct stack (
int top;
struct dataarea item[MAXSTACK];
Data Structures s.top = -1;
/ * I n i t i a l h e dummy d a t a area. */
currarea.param = 0;
currarea.x=O;
currarea.y=O;
currarea.retaddr=O;
/*Push the dummy d a t a area on the stack*/
push(&s, &cumarea);
/*set the parameter and the return address
o f the current data area t o t h e i r
proper values. */
currarea.param = n;
currarea.retaddr=l;
start :/*This i s the beginning o f the simulated
factorial routine. */
i f (currarea. param == 0){
/*Simul ate return(1) */
result =l;
i=currarea.retaddr;
popsub(&s ,&currarea) ;
switch (i){
case 1: goto labell;
case 2: goto label2;
}/*end switch*/
}/*end i f * /
currarea.x=currarea.param-1;
/*simul a tion o f recursived call t o fact. */
push(&s, &cumarea) ;
currarea.param = currarea.x;
currarea.retaddr=2;
goto start;
label2:/*This i s the point t o which we return from
the recursive c a l l . s e t currarea.y t o the returned value
currarea.y=result;
/*simulation o f return(n*y) */
result=currarea.pararn*currarea.y;
i=currarea.retaddr;
popsub(&s, &currarea);
switch (l){
case 1: goto labell;
case 2: goto label2;
}/*end switch*/
labell:/*At t h i s point we return t o the main routine. */
return (result) ;
)/*end simfact */
Work through the program for n = 5 and be sure that you understand what the program does and
how it does it. Notice that no space was reserved in the data area for temporaries, since they
need not be saved for later use. The temporary location that holds the value of n*y in the
original recursive routine is simulated by the temporary for
. .
currarea param=currarea y in the simulating routine. This is not the case in general.
For example, if a recursive function funct contained a statement such as

we have to save the temporary for funct (b) during the recursive call on funct(d). However,
this is not required in our example.

So, which temporary variables need to be stacked? We must save a variable on the stack only if
the value at the point of initiation of recursive calls must be reused after return from that call.
Let us examine whether this is so regarding the variables n,x and y. Clearly, we do not have to
Stacks and Queues

the old value of n must be used in the multiplication after return from the recursive call on fact.
However this is not so for x and y. In fact, the value of y is not even defined at the ~ o i nof
t the
recursive call, we need not put it on the stack. Similarly, we need not stack x also because we
do not use it again after returning.

If we declare x and y as global variables rather than within the recursive function. the routine
will work fine. Thus, automatic stacking and unstacking of x and Y is unnecessary.

Another issue is whether the return address is really needed in the stack. We make only one
textual recursive call to fact and so there is only one return address within fact. But, suppose a
dummy data area had not been stacked upon initialising the simulation. Then, a data area is
placed on the stack only in simulating a recursive call. When the stack is popped in returning
from a recursive call, that area is removed from the stack. However, when we attempt to pop the
stack in simulating a return to the main procedure, an underflow will occur. We can test for this
underflow by using popandtest rather than popsub and when it does occur we can return
directly to the outside calling routine rather than through a local label. This means that one of
the return addresses can be eliminated. Since this leaves only a single possible return address, it
need not be placed on the stack.

Thus, we have reduced the data area and the stack may be declared by
#define MAXSTACK 50

The current data area is reduced to a single variable declared by


i n t currparam;

The program is more comprehensible now:


i n t simfact(int n ) ;

struct stack s ;
short int und;
long int r e s u l t , y ;
int currparam,x;

s . t o p = -1;
currparam = n;
s t a r t :/*This i s the beginning o f the simulated
factorial routine., */
i f (currparam == O){
/* sirnubtion o f return(l)*/
r e s u l t = 1;
popandtest(&s, &currparam, &und);
switch(und) {
case FALSE: goto label2;
case TRUE: goto l a b e l l ;
)/*End switch*/
/*cumparam !=O a/
x = currparam-1;
/*simulation o f the recursive call t o fact*/
push(&s, currparam);
currparam = x;
goto s t a r t ;
label2: his i s the point t o which we return from
recursive c a l l . S e t y t o the returned
Data Structures

case FALSE: goto l a b e l 2 ;


)/*End Switch*/
labell:/*At t h i s p o i n t we r e t u r n t o t h e main
routine*/
return(resu1t);
)/*end simfact*/
Still, the program is far from ideal. The goto statements interrupt the flow of thought at a time
when one might understand what is happening. Let us see if we can improve the program
further.

The statement

popandtest(&s,&currparam, &und);
switch (und){
case TRUE: goto l a b e l l ;
case FALSE: goto l a b e l 2 ;
)/*End Switch*/

is repeated twice for the two cases currparam == 0 and currparam ! = 0. The two
sections can be combined in one.

Also, the two variables x and currparam are assigned values from each other and are never in
use simultaneously. Therefore, we can combine them as one variable and refer to it as x. The
same is true of r e s u l t and y. We combine them into a single variable Y.After these changes
the program becomes:

struct stack {
int t o p ;
int param[MAXSTACK];

int s i m f a c t ( i n t n)

struct stack s ;
short int und;
int x;
long int y ;
s. t o p = -1;
x=n ;
s t a r t : / * T h i s is t h e beginning o f t h e simulated
f a c t o r i a l r o u t i n e . */
i f ( x == 0)
y=l
else {
push(&s,x--);
goto s t a r t ;
)/*end else*/
l a b e l l : popandtest(&s, &x, &und)
i f (und == TRUE)
return (y) ;
l a b e l 2 :y *= x ;
goto l a b e l l ;
)/*end simfact */

There are two loops in the program.

1) The loop that consists of the entire if statement, labelled s t a r t . This loop is exited when
x equals 0,at which point y is set to 1 and execution proceeds to the label l a b e l l .
2) The loop that begins at label l a b e l 1 and ends with the statement goto l a b e l l . This Stacks and Que
loop is exited when the stack has been emptied and underflow occurs, at which point a
return is executed. These loops can be easily transformed into explicit while loops as
follows:
/*Subtraction 1oop*/
s t a r t : while(x != 0)
push(&s, x--);
y = 1;

}/>?end while*/
return (y) ;

Let us examine these two loops more closely. x starts off at the value of the input parameter n
and is reduced by 1 each time that the subtraction loop is repeated. Each time x is set to a new
value, the old value of x is saved on the stack. This continues until x is 0. Thus, after the first
loop has been executed the stack contains, from top to bottom, the integers 1 to n.

The multiplication loop merely removes each of these values from the stack and sets y to the
product of the popped value and the old value of y. Since we know what the stack contains at the
start of the multiplication loop, why bother popping the stack? We can use those values directly.
We can eliminate the stack and the first loop entirely and replace the multiplication loop with a
loop that multiplies Y by each of the integer from 1 to n in turn. The resulting program is
i n t simfact(int n)

int x;

y *= x ;
return (v):

This program is but a direct C implementation using iteration!

In multiuser system, there will be request,; fro n different users for CPU time. The operating
system puts them in queue and they are dispo: ed on FIFO(First In, First Out) basic. We will
i discuss the queue data structure and the opers ions that it allows in this section. Similar to stack
operations, operations that can be carried out In a queue are:
1) Create a queue.
P
2) Check whether a queue is empty.
3) Check whether a queue is full.
4) Add item at the rear of the queue(enqueue).
5) Remove item from front of queue(dequeue).
6 ) Read the front of the queue.
t 7) Print the entire queue.
I
I As we did in the case of stacks, we can give a array representation of a queue. We define a
queue as a structure containing the array and two variables, front and rear to denote the present
1 position of its front and rear elements.
E
We may define a queue as follows:
~ t aStructures const max = 100;
typedef struct q-type{
elementtype queue[max];
int front, rear;
IQtype ;
As an example of this representation of a queue, consider a queue of size 6. Assume that queue
is initially empty. We want to insert elements RED, BLACK and BLUE, delete RED and
BLACK and insert GREEN, WHITE and YELLOW.

Following figure gives a trace of the queue contents for this sequence of operations:

Now, if we try to insert ORANGE, an overflow occurs even though the first two cells are free.
To avoid this drawback, we can arrange these elements in a circular fashion with QUEUE[O]
following QUEUE[N-I]. It is then called a circular array representation. We may depict a
circular queue as shown in Fig. 5. We also initialise the values of q.front and q.rear to

Head

max-1. So, initially, when the queue is empty, q->front and q->rear have the same value.
The procdeure for checking whether a circular queue is empty and for inserting and elements in
a circular queue are given below:
int empty(Qtype *q)
t
return((q->front == q->rear)?l:O);
I
void qinsert(Qtype *q, int x)

int newrear;
i f (q->rear == max-1)
newrear = 0 ;
else
newrear = q->rear + 1;
i f (newrear == q->front) ;
Error("QUEUE OVERFLOW");
else{
q->rear=newrear;
1 60 q->queue[q->rear]=x;
1 Stacks and Que

int qdelete(Qtype *q)

exit(1) ;
1
if (q->front == max-1)
q->front = 0;
else
(q->front)++;
r e t u r n (q->queue[q->front 1) ;

1 Queues are important in simulation models. They serve several purposes like repositories for
scheduled events, holding areas for entities moving through the system etc.

Similarly, we may write procedures for other operations on queues.

The second approach for implementing queues is by using the dynamic storage allocation
through the use of pointers. We can define a queue consisting of records where each record
contains a pointer to the record that comes after it. Therefore, we may declare a queue as
s t r u c t qrec{
elementtype data;
s t r u c t qrec *next;
1;
struct qrec *qptr

We must also specify the items at the front and rear of the queue. This may be done by the
following declaration.
struct qtype{
struct qrec *front ;
struct qrec *rear;
1;
qtYPe q;
This kind of an implementation is a singly linked list implementation of the queue. Recall the
Queue implementation using circular arrays. Similarly, we can implement queues using circular
lists. In this list, each node points to the next and the chain of pointers eventually form a loop
back to the first one.

In such a case the declaration becomes simulified as follows:


s t r u c t qrec{
elementtype data;
s t r u c t qtype next;

struct qrec xqtype;


struct qrec *q;

You may notice that circular list implementation requires special attention for insertion and
deletion with no elements or with just one element.

13.6 PRIORITY QUEUES

Many applications involving queues require priority queues rather than simple FIFO strategy.
Each queue element has a associated priority value and the elements are served on a priority
basis instead of usine the order of adval. For elements of same ~rioritv.the FIFO order is used.
L
Stacks and Queues
if ( ! IsEmpty(S))
return S->data;
return 0;
1
Function for printing the stack.
void print-stack(1tem * S)
i f (IsEmpty(S))
printf("The stack is empty.");
I else (
printf("Printing elements in the stack..\nH);
. while (S->next != NULL) .I
printf("%d\nW, S->data);

A program that creates the stack and carries out stack operations.
void Error(char *message) ;
int main()
1
Item *mystack = NULL;
Push(4, &mystack);
Push(5, &mystack);
Push(7, &mystack);
print-stack(myStack);
Pop(&myStack);
printf("E1ement on top is \n%d", Top(myStack));
return 0;

1
E3) int ishigher(char opl, char op2)
if( (opl == '+' ( 1 opl == ' - ' ) && (0p2 == '*'I)
return (0);
else
return (1);
1
E4) /+Program-13.3. A program to evaluate an
expression in RPN. File name: uni tl3-evaluate-RPN. c*/
#include tstdio.h>
#include tstdlib.h>
#include tctype.h>
tdefi ne MALSTRING 20
typedef struct node (
int data;
str uct node *next ;
1 Item;
int IsEmpty(1tem * S);
void EmptyStack(1tem ** S);
void Push(int x, Item ** S);
int Top(1tem * S);
void Pop(1tem ** S);
void print-stack(1tem * S);
void Error(char *message) ;
int ishigher(char opl, char op2); 63
Data Structures char *infixZrpn(char *input);
int eval(char op, int a, int b);
int main()
C
int i,j,opl,op2;
char out[MALSTRING];
Item *mystack = NULL;
infixZrpn(out);
printf("RPN form is\nV);
for(i=O;out[i] != '\nl;i++)
printf("%c",out[i]);
printf("\nn);
for(i = 0; out[i] != '\nl;i++){
I f (isdigit (out [i] ) )
Push(out[i]-'O',&myStack);
else{

return 0;
I
int IsEmpty(1tem * S)
C
if (S != NULL)
return 0;
else
return 1;
void EmptyStack(1tem ** S)
C
Item *current = *S;
if (S == NULL)
printf("Error! No stack to empty!");
else
while ( ! IsEmpty(current))
Pop(S) ;
1
void Push(int x, Item ** S)
{
Item *tmp;
tmp = malloc(sizeof(Item));

exit (1);
I else {
tmp->data = x;
tmp->next = *S ;
*S = tmp;
1
I
int Top(1tem * S)
{
if ( ! IsEmpty(S))
return S->data;
printf("Empty Stack!");
return 0 :
Stacks and Queues
void Pop(1tem ** S)
Item *current, *Firstcell;
current = *S;
if (IsEmpty(*S)) {
printf("Empty Stack");
return ;
) else {
Firstcell = current;
*S = current->next:

void print-stack(1tem * S)
{
if (IsEmpty(S))
printf("The stack is empty.");
else {
printf("Printing elements in the stack..\nU);
while (S->next != NULL) {
printf("%d\nU, S->data);
S = S->next;

1
void Error(char *message)

If( (opl == '+' 1 ) opl == ' - ' ) && (op2 == ' * ' ) )
return (0);
,.' else
return (1):
char *infixZrpn(char *out)
Item *S=NULL;
char c;
int i=O;
whiie((c=getchar()) != '\nl){
i f (c == ' ' )
continue ;
if (isdigit(c))
out[i++]=c;
else if (IsEmpty(S))
Push(c,&S);
eiseJ
Data Structures

i n t eval(char op, i n t a , i n t b )
{
switch (op){
case('+') :
return(a + b);
case('-'):
r e t u r n (b- - a) ;
case('+'):
return(a*b) ;
I
I

You might also like