0% found this document useful (0 votes)
7 views33 pages

Unit Iii

This document discusses linear data structures, specifically stacks and queues, detailing their definitions, operations, and implementations. It explains the Last In First Out (LIFO) principle of stacks, including push and pop operations, and provides both static (array) and dynamic (linked list) implementation methods. Additionally, it covers applications of stacks such as evaluating arithmetic expressions and balancing symbols in programming.

Uploaded by

sebinraj2010
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)
7 views33 pages

Unit Iii

This document discusses linear data structures, specifically stacks and queues, detailing their definitions, operations, and implementations. It explains the Last In First Out (LIFO) principle of stacks, including push and pop operations, and provides both static (array) and dynamic (linked list) implementation methods. Additionally, it covers applications of stacks such as evaluating arithmetic expressions and balancing symbols in programming.

Uploaded by

sebinraj2010
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/ 33

UNIT III LINEAR DATA STRUCTURES – STACK & QUEUE

Stack ADT – Stack Model- Implementation of Stack – Applications – Queue ADT – Queue
model- Queue Implementation – Applications

STACK

• Stack is a Linear Data Structure that follows Last In First Out (LIFO) principle.
• Insertion and deletion can be done at only one end of the stack called TOP of the
stack.
• Example: - Pile of coins, stack of trays

Operations on a stack

• push, which is equivalent to an insert, and


• pop, which deletes the most recently inserted element.

STACK ADT:

Operations on Stack (Stack ADT)


Two fundamental operations performed on the stack are PUSH and POp.
(a) PUSH:
It is the process of inserting a new element at the Top of the stack.
For every push operation:
1. Check for Full stack ( overflow ).
2. Increment Top by 1. (Top = Top + 1)
3. Insert the element X in the Top of the stack.
(b) POP:

It is the process of deleting the Top element of the stack.

For every pop operation:

1. Check for Empty stack ( underflow ).


2. Delete (pop) the Top element X from the stack
3. Decrement the Top by 1. (Top = Top - 1 )

Exceptional Conditions of stack

1. Stack Overflow

An Attempt to insert an element X when the stack is Full, is said to be stack
overflow.
 For every Push operation, we need to check this condition.
2. Stack Underflow:

 An Attempt to delete an element when the stack is empty, is said to be stack


underflow.
 For every Pop operation, we need to check this condition.

12.4 Implementation of Stack

Stack can be implemented in 2 ways.

1. Static Implementation (Array implementation of Stack)


2. Dynamic Implementation (Linked List Implementation of Stack)

12.4.1 Array Implementation of Stack

 Each stack is associated with a Top pointer.


 For Empty stack, Top = -1.
 Stack is declared with its maximum size.
Array Declaration of Stack:
#define ArraySize 5
int S [ Array Size];
or
int S [ 5 ];
(i) Stack Empty Operation:
 Initially Stack is Empty.
 With Empty stack Top pointer points to – 1.
 It is necessary to check for Empty Stack before deleting (pop) an element from the stack.

Routine to check whether stack is empty

int IsEmpty ( Stack S )


{
if( Top = = - 1 )
return(1);
}

(ii) Stack Full Operation:


 As we keep inserting the elements, the Stack gets filled with the elements.
 Hence it is necessary to check whether the stack is full or not before inserting a new
element into the stack.

Routine to check whether a stack is full


int IsFull ( Stack S )

{ if( Top = = Arraysize – 1 )

return(1);

(ii) Push Operation

 It is the process of inserting a new element at the Top of the stack.


 It takes two parameters. Push(X, S) the element X to be inserted at the Top of the Stack
S.
 Before inserting an Element into the stack, check for Full Stack.
 If the Stack is already Full, Insertion is not possible.
 Otherwise, Increment the Top pointer by 1 and then insert the element X at the Top of the
Stack.
Routine to push an element into the stack

void Push ( int X , Stack S )


{
if ( Top = = Arraysize - 1)
Error(“Stack is full!!Insertion is not possible”);
else
{ Top = Top + 1;
S [ Top ] =X;
}
}

(iv) Pop Operation


 It is the process of deleting the Top element of the stack.
 It takes only one parameter. Pop(X).The element X to be deleted from the Top of the
Stack.
 Before deleting the Top element of the stack, check for Empty Stack.
 If the Stack is Empty, deletion is not possible.
 Otherwise, delete the Top element from the Stack and then decrement the Top pointer by
1.
Routine to Pop the Top element of the stack
void Pop ( Stack S )
{
if ( Top = = - 1)
Error ( “Empty stack! Deletion not possible”);
else
{ X = S [ Top ] ;
Top = Top – 1 ;
}
}
(v) Return Top Element
 Pop routine deletes the Top element in the stack.
 If the user needs to know the last element inserted into the stack, then the user can return
the Top element of the stack.
 To do this, first check for Empty Stack.
 If the stack is empty, then there is no element in the stack.
 Otherwise, return the element which is pointed by the Top pointer in the Stack.

Routine to return top Element of the stack

int TopElement(Stack S)
{
if(Top==-1)
{
Error(“Empty stack!!No elements”);
return 0;
}
else
return S[Top];
}

Linked list implementation of Stack


 Stack elements are implemented using SLL (Singly Linked List) concept.
 Dynamically, memory is allocated to each element of the stack as a node.
Type Declarations for Stack using SLL
struct node;
typedef struct node *stack;
typedef struct node *position;
stack S;
struct node{ int
data; position
next;};
int IsEmpty(Stack S);
void Push(int x, Stack S);
void Pop(Stack S);
int TopElement(Stack S);
(i) Stack Empty Operation:
 Initially Stack is Empty.
 With Linked List implementation, Empty stack is represented as S -> next = NULL.
 It is necessary to check for Empty Stack before deleting ( pop) an element from the stack.
Routine to check whether the stack is empty S

int IsEmpty( Stack S)


HEADER NULL
{
if ( S -> next = = NULL)
EMPTY STACK
return ( 1 );
}

(ii) Push Operation


 It is the process of inserting a new element at the Top of the stack.
 With Linked List implementation, a new element is always inserted at the Front of the
List.(i.e.) S -> next.
 It takes two parameters. Push(X, S) the element X to be inserted at the Top of the StackS.
 Allocate the memory for the newnode to be inserted.
 Insert the element in the data field of the newnode.
 Update the next field of the newnode with the address of the next node which is stored
in the S -> next.

Header

30 20 10 NULL

40

newnode
Before Insertion
Push routine /*Inserts element at front of the list
void push(int X, Stack S)
{
Position newnode, Top;
newnode = malloc (sizeof( struct node ) );
newnode -> data = X;
newnode -> next = S -> next;
S -> next = newnode;
Top = newnode;
}

Header

40 30 20 10 NULL

After Insertion
TOP
(iii) Pop Operation
 It is the process of deleting the Top element of the stack.
 With Linked List implementations, the element at the Front of the List
(i.e.) S -> next is always deleted.
 It takes only one parameter. Pop(X).The element X to be deleted from the Front of the
List.
 Before deleting the front element in the list, check for Empty Stack.
 If the Stack is Empty, deletion is not possible.
 Otherwise, make the front element in the list as “temp”.
 Update the next field of header.
 Using free ( ) function, Deallocate the memory allocated for temp node.
PANIMALA
S

Header

40 30 20 10 NULL

TOP
Before Deletion
Pop routine /*Deletes the element at front of list
void Pop( Stack S )
{
Position temp, Top;
Top = S -> next;
if( S -> next = = NULL)
Error(“empty stack! Pop not possible”);
else
{
Temp = S -> next;
S -> next = temp -> next;
free(temp);
Top = S -> next;
}}

Header

40 30 20 10 NULL

HEADER

30 20 10 NULL
After Deletion
(iv) Return Top Element
 Pop routine deletes the Front element in the List.
 If the user needs to know the last element inserted into the stack, then the user can
return the Top element of the stack.
 To do this, first check for Empty Stack.
 If the stack is empty, then there is no element in the stack.
 Otherwise, return the element present in the S -> next -> data in the List.

Routine to Return Top Element


int TopElement(Stack S)

if(S->next==NULL)

error(“Stack is empty”);

return 0;

else

return S->next->data;

}
S

Header

40 30 20 10 NULL

TOP
APPLICATIONS OF STACK
The following are some of the applications of stack:

1. Evaluating the arithmetic expressions


o Conversion of Infix to Postfix Expression
o Evaluating the Postfix Expression
2. Balancing the Symbols
3. Function Call
EVALUATING THE ARITHMETIC EXPRESSION
There are 3 types of Expressions
 Infix Expression
 Postfix Expression
 Prefix Expression

INFIX:

The arithmetic operator appears between the two operands to which it is being
applied.

POSTFIX:

The arithmetic operator appears directly after the two operands to which it applies.
Also called reverse polish notation.
PREFIX:
The arithmetic operator is placed before the two operands to which it applies. Also
called polish notation.

Evaluating Arithmetic Expressions

1. Convert the given infix expression to Postfix expression


2. Evaluate the postfix expression using stack.

Algorithm to convert Infix Expression to Postfix Expression:

Read the infix expression one character at a time until it encounters the delimiter “#”

Step 1: If the character is an operand, place it on the output.

Step 2: If the character is an operator, push it onto the stack. If the stack operator has a higher or
equal priority than input operator then pop that operator from the stack and place it onto the
output.

Step 3:If the character is left parenthesis, push it onto the stack

Step 4:If the character is a right parenthesis, pop all the operators from the stack till it encounters
left parenthesis, discard both the parenthesis in the output.
E.g. Consider the following Infix expression: - A*B+(C-D/E)#

Read char Stack Output

A A

*
A

B
+ AB
*

+ AB*

( AB*
(
+
Read char Stack Output

C AB*C
(
+

- AB*C
-
(
+

- AB*CD
D
(
+

AB*CD
/
/
-
(
+

AB*CDE
E /
-
(
+

AB*CDE/-

) /
-
(
+
Read char Stack Output

AB*CDE/-+

Output: Postfix expression:- AB*CDE/-+

Evaluating the Postfix Expression

Algorithm to evaluate the obtained Postfix Expression

Read the postfix expression one character at a time until it encounters the delimiter „#‟

Step 1: If the character is an operand, push its associated value onto the stack.

Step 2: If the character is an operator, POP two values from the stack, apply the operator to
them and push the result onto the stack.

E.g consider the obtained Postfix expression:- AB*CDE/-+

Operand Value
A 2
B 3
C 4
D 4
E 2

Char Read Stack

A 2

3
B
2
Char Read Stack

* 6

4
C 6

4
D 4
6

2
/ 4
6

2
- 6

+ 8
OUTPUT = 8

Example 2: Infix expression:- (a+b)*c/d+e/f#

Read char Stack Output

(
(

a a
(
+ a
+
(

b ab
+
(

) ab+

* ab+

c ab+c

/ ab+c*

d ab+c*d

ab+c*d/
+

21
e ab+c*d/e

/ ab+c*d/e
/
+

f ab+c*d/ef
/
+

# ab+c*d/ef/+

Postfix expression:- ab+c*d/ef/+

Evaluating the Postfix Expression

Operand Value
a 1
b 2
c 4
d 2
e 6
f 3
Char Read Stack

a 1

2
b
1

+ 3

4
c 3

* 12

2
d 12

/ 6

6
e 6

3
F 6
6

2
/ 6

+ 8

Output = 8
BALANCING THE SYMBOLS

 Compilers check the programs for errors, a lack of one symbol will cause an error.
 A Program that checks whether everything is balanced.
 Every right parenthesis should have its left parenthesis.
 Check for balancing the parenthesis brackets braces and ignore any other character.

Algorithm for balancing the symbols


Read one character at a time until it encounters the delimiter `#'.
Step 1 : - If the character is an opening symbol, push it onto the stack.
Step 2 : - If the character is a closing symbol, and if the stack is empty report an error as
missing opening symbol.
Step 3 : - If it is a closing symbol and if it has corresponding opening symbol in the stack, POP
it from the stack. Otherwise, report an error as mismatched symbols.
Step 4 : - At the end of file, if the stack is not empty, report an error as Missing closing symbol.
Otherwise, report as balanced symbols.
E.g. Let us consider the expression ((B*B)-{4*A*C}/[2*A]) #

((B*B)-{4*A*C}/[2*A]) #

Read Character Stack

( (
(
)
(

{ {
(

}
(

[ [
(

]
(

Empty stack, hence the symbols the balanced in the given expression.
Example for unbalanced symbols:
FUNCTION CALLS
 When a call is made to a new function, all the variables local to the calling routine need
to be saved by the system. Otherwise the new function will overwrite the calling
routine's variables.
 The current location in the routine must be saved so that the new function knows where
to go after it is done.
 The reason that this problem is similar to balancing symbols is that a function call and
function return are essentially the same as an open parenthesis and closed parenthesis,
so the same ideas should work.
 When there is a function call, all the important information that needs to be saved, such
as register values (corresponding to variable names) and the return address is saved "on
a piece of paper" in an abstract way and put at the top of a pile. Then the control is
transferred to the new function, which is free to replace the registers with its values.
 If it makes other function calls, it follows the same procedure. When the function wants
to return, it looks at the "paper" at the top of the pile and restores all the registers. It then
makes the return jump.
 The information saved is called either an activation record or stack frame.
 There is always the possibility that you will run out of stack space by having too many
simultaneously active functions. Running out of stack space is always a fatal error.
 In normal events, you should not run out of stack space; doing so is usually an
indication of runaway recursion. On the other hand, some perfectly legal and seemingly
innocuous program can cause you to run out of stack space.
A bad use of recursion: printing a linked list
void /* Not using a header */

print_list( LIST L )

{ if( L != NULL )

print_element( L->element );

print_list( L->next ); } }
 The above routine prints out a linked list, is perfectly legal and actually correct. It properly
handles the base case of an empty list, and the recursion is fine. This program can be proven
correct.
 Activation records are typically large because of all the information they contain, so this program
is likely to run out of stack space. This program is an example of an extremely bad use of
recursion known as tail recursion. Tail recursion refers to a recursive call at the last line.
 Tail recursion can be mechanically eliminated by changing the recursive call to a goto receded by
one assignment per function argument.
 This simulates the recursive call because nothing needs to be saved -- after the recursive call
finishes, there is really no need to know the saved values. Because of this, we can just go to the
top of the function with the values that would have been used in a recursive call.
The below program is the improved version. Removal of tail recursion is so simple that some compilers
do it automatically.

Printing a list without recursion

Void print_list( LIST L ) /* No header */

top:

if( L != NULL )

print_element( L->element );L = L-

>next;

goto top;

}
Recursion can always be completely removed. But doing so can be quite tedious. The non- recursive
programs are generally faster than recursive programs; the speed advantage rarely justifies the lack of
clarity that results from removing the recursion.
QUEUES

 Queue is a Linear Data Structure that follows First in First out (FIFO) principle.
 Insertion of element is done at one end of the Queue called “Rear “end of the Queue.
 Deletion of element is done at other end of the Queue called “Front “end of the Queue.
 Example: - Waiting line in the ticket counter.

Front End
RearEnd
QUEUE Q
Deletion
Insertion

Queue Model

Front Pointer:-

It always points to the first element inserted in the Queue.

Rear Pointer:-

It always points to the last element inserted in the Queue.

For Empty Queue:-

Front (F) = - 1

Rear (R) = - 1

Operations on Queue

Fundamental operations performed on the queue are

1. EnQueue
2. DeQueue
(i) EnQueue operation:-

 It is the process of inserting a new element at the rear end of the Queue.
 For every EnQueue operation
o Check for Full Queue
o If the Queue is full, Insertion is not possible.
o Otherwise, increment the rear end by 1 and then insert the element in the rear end
of the Queue.

(ii) DeQueue Operation:-

 It is the process of deleting the element from the front end of the queue.
 For every DeQueue operation
o Check for Empty queue
o If the Queue is Empty, Deletion is not possible.
o Otherwise, delete the first element inserted into the queue and then increment the
front by 1.

Exceptional Conditions of Queue

 Queue Overflow
 Queue Underflow

(i) Queue Overflow:

 An Attempt to insert an element X at the Rear end of the Queue when the
Queue is full is said to be Queue overflow.
 For every Enqueue operation, we need to check this condition.
(ii) Queue Underflow:
 An Attempt to delete an element from the Front end of the Queue when the
Queue is empty is said to be Queue underflow.
 For every DeQueue operation, we need to check this condition.
Queue can be implemented in two ways.

1. Implementation using Array (Static Queue)


2. Implementation using Linked List (Dynamic Queue)

Implementation using Array

Array Declaration of Queue:


#define ArraySize 5
int Q [ ArraySize];
or
int Q [ 5 ];

Initial Configuration of Queue:

(i) Queue Empty Operation:


Initially Queue is Empty.
 With Empty Queue, Front ( F ) and Rear ( R ) points to – 1.
It is necessary to check for Empty Queue before deleting (DeQueue) an element from the
Queue (Q).

int IsEmpty ( Queue Q )


{
if( ( Front = = - 1) && ( Rear = = - 1 ) )
return ( 1 );
}int IsEmpty ( Queue Q )

if( ( Front = = - 1) && ( Rear = = - 1 ) )

return ( 1 );

}
(ii) Queue Full Operation

As we keep inserting the new elements at the Rear end of the Queue, the Queue becomes
full.
When the Queue is Full, Rear reaches its maximum Arraysize.
For every Enqueue Operation, we need to check for full Queue condition.

Routine to check for Full Queue


int IsFull( Queue Q )

if ( Rear = = ArraySize - 1 )

return ( 1 );

Enqueue Operation

It is the process of inserting a new element at the Rear end of the Queue.
It takes two parameters, Enqueue(X, Q). The elements X to be inserted at the Rear end of
the Queue Q.
Before inserting a new Element into the Queue, check for Full Queue.
If the Queue is already Full, Insertion is not possible.
Otherwise, Increment the Rear pointer by 1 and then insert the element X at the Rear end
of the Queue.
If the Queue is Empty, Increment both Front and Rear pointer by 1 and then insert the
element X at the Rear end of the Queue.

Routine to Insert an Element in a Queue

void EnQueue (int X , Queue Q)


{
if ( Rear = = Arraysize - 1)
print (" Full Queue !!!!. Insertion not
possible");
else if (Rear = = - 1)
{
Front = Front + 1;
Rear = Rear + 1;
Q [Rear] = X;
}
else
{
Rear = Rear + 1;
Q [Rear] = X;
}
}

(iii) DeQueue Operation


It is the process of deleting a element from the Front end of the Queue.
It takes one parameter, DeQueue (Q). Always front element in the Queue will be deleted.
Before deleting an Element from the Queue, check for Empty Queue.
If the Queue is empty, deletion is not possible.
If the Queue has only one element, then delete the element and represent the empty queue
by updating Front = - 1 and Rear = - 1.
If the Queue has many Elements, then delete the element in the Front and move the Front
pointer to next element in the queue by incrementing Front pointer by 1.

ROUTINE FOR DEQUEUE

void DeQueue ( Queue Q )


{
if ( Front = = - 1)
print (" Empty Queue !. Deletion not possible " );
else if( Front = = Rear )
{
X = Q [ Front ];
Front = - 1;
Rear = - 1;
}
else
{
X = Q [ Front ];
Front = Front + 1 ;
}
}

Linked List Implementation of Queue

 Queue is implemented using SLL (Singly Linked List ) node.


 Enqueue operation is performed at the end of the Linked list and DeQueue
operation is performed at the front of the Linked list.
 With Linked List implementation, for Empty queue
Front = NULL & Rear = NULL
Linked List representation of Queue with 4 elements

Header

10 20 30 40 NULL

Front Rear

Declaration for Linked List Implementation of Queue ADT

struct node;
typedef struct node * Queue;
typedef struct node * position;
int IsEmpty (Queue Q);
Queue CreateQueue (void);
void MakeEmpty (Queue Q);
void Enqueue (int X, Queue Q);
void Dequeue (Queue Q);
struct node
{
int data ;
position next;
}* Front = NULL, *Rear = NULL;
(i) Queue Empty Operation:
 Initially Queue is Empty.
 With Linked List implementation, Empty Queue is represented as S -> next = NULL.
 It is necessary to check for Empty Queue before deleting the front element in the Queue.

ROUTINE TO CHECK WHETHER THE QUEUE IS EMPTY

int IsEmpty (Queue Q


{ Q

return (1); Header NULL


}

(ii) EnQueue Operation Empty Queue

 It is the process of inserting a new element at the Rear end of the Queue.
 It takes two parameters, EnQueue ( int X , Queue Q ). The elements X to be inserted into
the Queue Q.
 Using malloc ( ) function allocate memory for the newnode to be inserted into the Queue.
 If the Queue is Empty, the newnode to be inserted will become first and last node in the
list. Hence Front and Rear points to the newnode.
 Otherwise insert the newnode in the Rear -> next and update the Rear pointer.

Routine to EnQueue an Element in Queue

void EnQueue ( int X, Queue Q )


{
struct node *newnode;
newnode = malloc (sizeof (struct node));
if (Rear = = NULL)
{

Q -> next = newnode;


Front = newnode;
Rear = newnode;
}
else
{

(iii) DeQueue Operation

It is the process of deleting the front element from the Queue.


It takes one parameter, Dequeue ( Queue Q ). Always element in the front (i.e) element pointed
by Q -> next is deleted always.
Element to be deleted is made “temp”.
If the Queue is Empty, then deletion is not possible.
If the Queue has only one element, then the element is deleted and Front and Rear pointer is
made NULL to represent Empty Queue.
Otherwise, Front element is deleted and the Front pointer is made to point to next node in the list.
The free ( ) function informs the compiler that the address that temp is pointing to, is unchanged
but the data present in that address is now undefined.

Routine to DeQueue an Element from the Queue

void DeQueue ( Queue Q )


{
struct node *temp;
if ( Front = = NULL )
Error (“Empty Queue!!! Deletion not possible.” );
else if (Front = = Rear)
{
temp = Front;
Q -> next = NULL;
Front = NULL;
Rear = NULL;
free ( temp );
}
else
{
temp = Front;
Q -> next = temp -> next;
Front = Front Next;
free (temp);
}

}
Applications of Queue

1. Serving requests on a single shared resource, like a printer, CPU task scheduling etc.
2. In real life, Call Center phone systems will use Queues, to hold people calling them in an
order, until a service representative is free.
3. Handling of interrupts in real-time systems. The interrupts are handled in the same order
as they arrive, First come first served.
4. Batch processing in operating system.
5. Job scheduling Algorithms like Round Robin Algorithm uses Queue.

CIRCULAR QUEUE

In Circular Queue, the insertion of a new element is performed at the very first location of the
queue if the last location of the queue is full, in which the first element comes just after the last
element.

 A circular queue is an abstract data type that contains a collection of data which allows
addition of data at the end of the queue and removal of data at the beginning of the
queue.
 Circular queues have a fixed size.
 Circular queue follows FIFO principle.
 Queue items are added at the rear end and the items are deleted at front end of the circular
queue
 Here the Queue space is utilized fully by inserting the element at the Front end if the rear
end is full.

Operations on Circular Queue

You might also like