0% found this document useful (0 votes)
3 views

Unit-III

Stack and Queue

Uploaded by

pofajon338
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 views

Unit-III

Stack and Queue

Uploaded by

pofajon338
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/ 24

Unit:III

Introduction – Array Representation of a Stack – Linked List Representation of a Stack - Stack


Operations - Algorithm for Stack Operations - Stack Applications: Tower of Hanoi - Infix to
postfix Transformation - Evaluating Arithmetic Expressions. Queue – Introduction – Array
Representation of Queue – Linked List Representation of Queue - Queue Operations -
Algorithm for Queue Operations - . Queue Applications: Priority Queue.
3.1 Introduction
A stack is an Abstract Data Type (ADT), commonly used in most programming languages. It is
named stack as it behaves like a real-world stack, for example – a deck of cards or a pile of plates,
etc.
This feature makes it LIFO data structure. LIFO stands for Last-in-first-out. Here, the element which
is placed (inserted or added) last, is accessed first. In stack terminology, insertion operation is
called PUSH operation and removal operation is called POP operation.

Stack Representation
The following fig 3.1 depicts a stack and its operations −

Fig 3.1 Stack Representation

3.2 Array representation of a Stack

A stack can be implemented by means of Array, Structure, Pointer, and Linked List. Stack can
either be a fixed size one or it may have a sense of dynamic resizing. Here, we are going to implement
stack using arrays, which makes it a fixed size stack implementation. First we have to allocate a
memory block of sufficient size to accommodate the full capacity of the stack. Then, starting from
the first location of the memory block, the items of the stack can be stored in a sequential fashion.
Fig 3.2 Representation of a stack

In Fig 3.2 a, Itemi denotes the ith item in the stack; l and u denote the index range of
the array in use; usually the values of these indices are 1 and SIZE respectively. TOP is a
pointer to point the position of the array up to which it is filled with the items of the stack.

3.3 Linked List Representation of Stacks

Although array representation of stacks is very easy and convenient but it allows the
representation of only fixed sized stacks. In several applications, the size of the stack may
vary during program execution. An obvious solution to this problem is to represent a stack
using a linked list. A single linked list structure is sufficient to represent any stack. Here,
the DATA field is for the ITEM, and the LINK field is, as usual, to point to the next' item.
Above Figure b depicts such a stack using a single linked list. In the linked list
representation, the first node on the list is the current item that is the item at the top of the
stack and the last node is the node containing the bottom-most item. Thus, a PUSH
operation will add a new node in the front and a POP operation will remove a node from
the front of the list is shown in Fig 3.2 b.
3.4 Stack Operations
Stack operations may involve initializing the stack, using it and then de-initializing it. Apart
from these basic stuffs, a stack is used for the following two primary operations −
• push() − Pushing (storing) an element on the stack.
• pop() − Removing (accessing) an element from the stack.
When data is PUSHed onto stack.
To use a stack efficiently, we need to check the status of stack as well. For the same purpose, the
following functionality is added to stacks −
• peek() − get the top data element of the stack, without removing it.
• isFull() − check if stack is full.
• isEmpty() − check if stack is empty.
At all times, we maintain a pointer to the last PUSHed data on the stack. As this pointer always
represents the top of the stack, hence named top. The top pointer provides top value of the stack
without actually removing it.
3.5 Algorithm for Stack Operations
Push Operation
The process of putting a new data element onto stack is known as a Push Operation is shown in
fig.3.3. Push operation involves a series of steps −
Step 1 − Checks if the stack is full.
Step 2 − If the stack is full, produces an error and exit.
Step 3 − If the stack is not full, increments top to point next empty space.
Step 4 − Adds data element to the stack location, where top is pointing.
Step 5 − Returns success.

Fig 3.3 Push Operation


If the linked list is used to implement the stack, then in step 3, we need to allocate space dynamically.

Algorithm for PUSH Operation

A simple algorithm for Push operation can be derived as follows −


procedure push

if stack is full
return null
endif
top ← top + 1
stack[top] ← data
end procedure

Pop Operation
Accessing the content while removing it from the stack, is known as a Pop Operation. In an array
implementation of pop() operation, the data element is not actually removed, instead top is
decremented to a lower position in the stack to point to the next value. But in linked-list
implementation, pop() actually removes data element and deallocates memory space is shown in
Fig.3.4.
A Pop operation may involve the following steps −
Step 1 − Checks if the stack is empty.
Step 2 − If the stack is empty, produces an error and exit.
Step 3 − If the stack is not empty, accesses the data element at which top is pointing.
Step 4 − Decreases the value of top by 1.
Step 5 − Returns success.

Fig 3.4 Pop Operation


Algorithm for Pop Operation
procedure pop: stack

if stack is empty
return null
endif
data ← stack[top]
top ← top - 1
return data
Displays the elements of a Stack
We can use the following steps to display the elements of a stack...

Step 1 - Check whether stack is EMPTY. (top == -1)

Step 2 - If it is EMPTY, then display "Stack is EMPTY!!!" and terminate the function.

Step 3 - If it is NOT EMPTY, then define a variable 'i' and initialize with top.
Display stack[i] value and decrement i value by one (i--).

Step 3 - Repeat above step until i value becomes '0'.


3.6 Stack Using Linked List
In linked list implementation of a stack, every new element is inserted as 'top' element. That
means every newly inserted element is pointed by 'top'. Whenever we want to remove an element
from the stack, simply remove the node which is pointed by 'top' by moving 'top' to its previous
node in the list. The next field of the first element must be always NULL.

Example

Fig 3.5 Linked List Representation


In the above Fig 3.5, the last inserted node is 99 and the first inserted node is 25. The order of
elements inserted is 25, 32,50 and 99.

Stack Operations using Linked List

push(value) - Inserting an element into the Stack

We can use the following steps to insert a new node into the stack...

Step 1 - Create a newNode with given value.

Step 2 - Check whether stack is Empty (top == NULL)

Step 3 - If it is Empty, then set newNode → next = NULL.

Step 4 - If it is Not Empty, then set newNode → next = top.

Step 5 - Finally, set top = newNode.


Algorithm

push(int value)

begin

newNode->data = value;

if(top == NULL)

newNode->next = NULL;

else

newNode->next = top;

top = newNode;

end

pop() - Deleting an Element from a Stack

We can use the following steps to delete a node from the stack...

Step 1 - Check whether stack is Empty (top == NULL).

Step 2 - If it is Empty, then display "Stack is Empty!!! Deletion is not


possible!!!" and terminate the function

Step 3 - If it is Not Empty, then define a Node pointer 'temp' and set it to 'top'.

Step 4 - Then set 'top = top → next'.

Step 5 - Finally, delete 'temp'. (free(temp)).


Algorithm

void pop()

begin

if(top == NULL)

print("\nStack is Empty!!!\n");

else

print("\nDeleted element: %d", temp->data);

top = temp->next;

free(temp);

endif

end

display() - Displaying stack of elements

We can use the following steps to display the elements (nodes) of a stack...

Step 1 - Check whether stack is Empty (top == NULL).

Step 2 - If it is Empty, then display 'Stack is Empty!!!' and terminate the function.

Step 3 - If it is Not Empty, then define a Node pointer 'temp' and initialize with top.

Step 4 - Display 'temp → data --->' and move it to the next node. Repeat the same
until temp reaches to the first node in the stack. (temp → next != NULL).

Step 5 - Finally! Display 'temp → data ---> NULL'.


Algorithm

void display()
begin
if(top == NULL)
print("\nStack is Empty!!!\n");
else{
struct Node *temp = top;
while(temp->next != NULL)
begin
print("%d--->",temp->data);
temp = temp -> next;
end
print("%d--->NULL",temp->data);
end

3.7 Stack Applications


3.7.1Tower of Hanoi
Tower of Hanoi is a mathematical puzzle which consists of three tower (pegs) and more than
one ring; as depicted in Fig.3.6.
Towers

Disks

Smallest

Largest

Fig.3.6 Tower of Hanoi


These rings are of different sizes and stacked upon in ascending order i.e. the smaller one sits
over the larger one. There are other variationsof puzzle where the number of disks increases,
but the tower count remains the same.
Rules
The mission is to move all the disks to some another tower without violating the sequence of
arrangement. The below mentioned are few rules which are to be followed for Tower of Hanoi
• Only one disk can be moved among the towers at any given time.
• Only the “top” disk can be removed.
• No large disk can sit over a small disk.

Steps for solving the Towers of Hanoi problem


The following steps are to be followed.
Step 1: Move n-1 disks from source to aux.
Step 2: Move nth disk from source to destination
Step 3: Move n-1 disks from aux to destination.
F i g . 3 . 7 , illustrates the step by step movement of the disks to implement Tower of Hanoi.

Step: 0

Step: 2

Fig 3.7 Tower of Hanoi


Step: 6

Fig 3.7 Tower of Hanoi


Done!

Fig.3.7 Tower of Hanoi


A recursive algorithm for Tower of Hanoi can be driven as followsSTART
Procedure Hanoi (disk, source, dest, aux)
IF disk = 0, THEN
Move disk from source to destELSE
Hanoi (disk-1, source, aux, dest) //Step1Move disk from source to dest //Step2 Hanoi
(disk-1, aux, dest, source) //Step3 ENDIF

END
3.7.2 Infix to postfix Transformation
There is an algorithm to convert an infix expression into a postfix expression. It uses a
stack; but in this case, the stack is used to hold operators rather than numbers. The purpose of the
stack is to reverse the order of the operators in the expression. It also serves as a storage structure,
since no operator can be printed until both of its operands have appeared.
In this algorithm, all operands are printed (or sent to output) when they are read. There are
more complicated rules to handle operators and parentheses.
Example:

1. A * B + C becomes A B * C +

The order in which the operators appear is not reversed. When the '+' is read, it has lower
precedence than the '*', so the '*' must be printed first.
We will show this in a table with three columns. The first will show the symbol currently being
read. The second will show what is on the stack and the third will show the current contents of the
postfix string. The stack will be written from left to right with the 'bottom' of the stack to the left.
current symbol operator stack postfix string

1 A A

2 * * A

3 B * AB

4 + + A B * {pop and print the '*' before pushing the '+'}

5 C + AB*C

6 AB*C+

The rule used in lines 1, 3 and 5 is to print an operand when it is read. The rule for line 2 is to push
an operator onto the stack if it is empty. The rule for line 4 is if the operator on the top of the stack
has higher precedence than the one being read, pop and print the one on top and then push the new
operator on. The rule for line 6 is that when the end of the expression has been reached, pop the
operators on the stack one at a time and print them.
2. A + B * C becomes A B C * +
Here the order of the operators must be reversed. The stack is suitable for this, since operators will
be popped off in the reverse order from that in which they were pushed.

current symbol operator stack postfix string

1 A A

2 + + A

3 B + AB

4 * +* AB
5 C +* ABC

6 ABC*+

In line 4, the '*' sign is pushed onto the stack because it has higher precedence than the '+' sign
which is already there. Then when the are both popped off in lines 6 and 7, their order will be
reversed.
3. A * (B + C) becomes A B C + *
A subexpression in parentheses must be done before the rest of the expression.

current symbol operator stack postfix string

1 A A

2 * * A

3 ( *( AB

4 B *( AB

5 + *(+ AB

6 C *(+ ABC

7 ) * ABC+

8 ABC+*

Since expressions in parentheses must be done first, everything on the stack is saved and the left
parenthesis is pushed to provide a marker. When the next operator is read, the stack is treated as
though it were empty and the new operator (here the '+' sign) is pushed on. Then when the right
parenthesis is read, the stack is popped until the corresponding left parenthesis is found. Since
postfix expressions have no parentheses, the parentheses are not printed.
4. A - B + C becomes A B - C +
When operators have the same precedence, we must consider association. Left to right association
means that the operator on the stack must be done first, while right to left association means the
reverse.
current symbol operator stack postfix string

1 A A

2 - - A

3 B - AB

4 + + AB-

5 C + AB-C

6 AB-C+

In line 4, the '-' will be popped and printed before the '+' is pushed onto the stack. Both operators
have the same precedence level, so left to right association tells us to do the first one found before
the second.
5. A * B ^ C + D becomes A B C ^ * D +
Here both the exponentiation and the multiplication must be done before the addition.

current symbol operator stack postfix string

1 A A

2 * * A

3 B * AB

4 ^ *^ AB

5 C *^ ABC

6 + + ABC^*

7 D + ABC^*D

8 ABC^*D+
When the '+' is encountered in line 6, it is first compared to the '^' on top of the stack. Since it has
lower precedence, the '^' is popped and printed. But instead of pushing the '+' sign onto the stack
now, we must compare it with the new top of the stack, the '*'. Since the operator also has higher
precedence than the '+', it also must be popped and printed. Now the stack is empty, so the '+' can
be pushed onto the stack.

6. A * (B + C * D) + E becomes A B C D * + * E +

current symbol operator stack postfix string

1 A A

2 * * A

3 ( *( A

4 B *( AB

5 + *(+ AB

6 C *(+ ABC

7 * *(+* ABC

8 D *(+* ABCD

9 ) * ABCD*+

10 + + ABCD*+*
11 E + ABCD*+*E

12 ABCD*+*E+

A summary of the rules follows:


1. Print operands as they arrive.
2. If the stack is empty or contains a left parenthesis on top, push the incoming operator
onto the stack.
3. If the incoming symbol is a left parenthesis, push it on the stack.
4. If the incoming symbol is a right parenthesis, pop the stack and print the operators until
you see a left parenthesis. Discard the pair of parentheses.
5. If the incoming symbol has higher precedence than the top of the stack, push it on the
stack.
6. If the incoming symbol has equal precedence with the top of the stack, use association.
If the association is left to right, pop and print the top of the stack and then push the
incoming operator. If the association is right to left, push the incoming operator.
7. If the incoming symbol has lower precedence than the symbol on the top of the stack,
pop the stack and print the top operator. Then test the incoming operator against the new
top of stack.
8. At the end of the expression, pop and print all operators on the stack. (No parentheses
should remain.)

Algorithm
int top = -1;
Infixtopostfix()
begin
print("\n\nRead the Infix Expression ? ");
Read infx
push('#');
while ((ch = infx[i++]) != '\0')
begin
if (ch == '(')
push(ch);
else if (isalnum(ch))
pofx[k++] = ch;
else if (ch == ')')
begin
while (s[top] != '(')
begin
pofx[k++] = pop();
elem = pop(); /* Remove ( */
end
else
while (pr(s[top]) >= pr(ch))
pofx[k++] = pop();
push(ch);
end
end

3.7.3 Evaluating Arithmetic Expressions


The stack organization is very effective in evaluating arithmetic expressions. Expressions are
usually represented in what is known as Infix notation, in which each operator is written between
two operands (i.e., A + B). With this notation, we must distinguish between ( A + B )*C and A +
( B * C ) by using either parentheses or some operator-precedence convention. Thus, the order of
operators and operands in an arithmetic expression does not uniquely determine the order in which
the operations are to be performed.
1. Polish notation (prefix notation) –
It refers to the notation in which the operator is placed before its two operands . Here no
parentheses are required, i.e., +AB
The procedure for getting the result is:
1. Convert the expression in Reverse Polish notation( post-fix notation).
2. Push the operands into the stack in the order they are appear.
3. When any operator encounter then pop two topmost operands for executing the operation.
4. After execution push the result obtained into the stack.
5. After the complete execution of expression the final result remains on the top of the
stack.
For example –
Infix notation: (2+4) * (4+6)
Post-fix notation: 2 4 + 4 6 + *
Result: 60
6. The stack operations for this expression evaluation is shown below:

Fig 3.8 Arithmetic Expressions

3.8 Queue
3.8.1 Introduction
Queue is also an abstract data type or a linear data structure, just like stack data structure,
in which the first element is inserted from one end called the REAR(also called tail), and the
removal of existing element takes place from the other end called as FRONT (also called head).
This makes queue as FIFO (First in First Out) data structure, which means that element inserted
first will be removed first. The process to add an element into queue is called Enqueue and the
process of removal of an element from queue is called Dequeue.

3.8.2 Array Representation of Queue


If queue is implemented using arrays, the size of the array should be fixed maximum allowing the
queue to expand or shrink.
Operations on a Queue
There are two common operations one in a queue. They are addition of an element to the
queue and deletion of an element from the queue. Two variables front and rear are used to point
to the ends of the queue. The front points to the front end of the queue where deletion takes place
and rear points to the rear end of the queue, where the addition of elements takes place. Initially,
when the queue is full, the front and rear is equal to -1.
Add(x)
An element can be added to the queue only at the rear end of the queue. Before adding an
element in the queue, it is checked whether queue is full. If the queue is full, then addition cannot
take place. Otherwise, the element is added to the end of the list at the rear side.

ADDQ(x)
If rear = MAX – 1
Then
Print “Queue is full”
Return
Else
Rear = rear + 1
A[rear] = x
If front = -1
Then
Front = 0
End if
End if
End ADDQ( )

Del( )
The del( ) operation deletes the element from the front of the queue. Before deleting and
element, it is checked if the queue is empty. If not the element pointed by front is deleted from
the queue and front is now made to point to the next element in the queue.

DELQ( )
If front = -1
Then
Print “Queue is Empty”
Return
Else
Item = A[front]
A[front] = 0
If front = rear
Then
Front = rear = -1
Else
Front = front + 1
End if
Return item
End if
End DELQ( )

3.8.3 Linked List Representation of Queue

Queue can be represented using a linked list. Linked lists do not have any restrictions on
the number of elements it can hold. Space for the elements in a linked list is allocated dynamically;
hence it can grow as long as there is enough memory available for dynamic allocation. The queue
represented using linked list would be represented as shown. The front pointer points to the front
of the queue and rear pointer points to the rear of the queue is shown in Fig 3.9.

Fig 3.9 Linked List


Addq(x)
In linked list representation of queue, the addition of new element to the queue takes place
at the rear end. It is the normal operation of adding a node at the end of a list.

ADDQ(x)
If front = NULL
Then
Rear = front = temp
Return
End if
Link(rear) = temp
Rear = link(rear)
End ADDQ( )
Delq( )
The delq( ) operation deletes the first element from the front end of the queue. Initially it
is checked, if the queue is empty. If it is not empty, then return the value in the node pointed by
front, and moves the front pointer to the next node.
DELQ( )
If front = NULL
Print “Queue is empty”
Return
Else
While front ≠ NULL
Temp = front
Front = link(front)
Delete temp
End while
End if
End DELQ( )
3.8.5 Queue Applications
3.8.5.1 Priority Queue
Priority Queue is more specialized data structure than Queue. Like ordinary queue, priority
queue has same method but with a major difference. In Priority queue items are ordered by key
value so that item with the lowest value of key is at front and item with the highest value of key is
at rear or vice versa is shown in Fig.3.10.
Basic Operations
• insert / enqueue − add an item to the rear of the queue.
• remove / dequeue − remove an item from the front of the queue.
Priority Queue Representation

Fig 3.10 Priority Queue


There is few more operations supported by queue which are following.
• Peek − get the element at front of the queue.
• isFull − check if queue is full.
• isEmpty − check if queue is empty.
Insert / Enqueue Operation
Whenever an element is inserted into queue, priority queue inserts the item according to its order.
Here we're assuming that data with high value has low priority is shown in Fig 3.11.
Fig 3.11 Insert/Enqueue operation
void insert(int data){
int i = 0;
if(!isFull()){
// if queue is empty, insert the data
if(itemCount == 0){
intArray[itemCount++] = data;
}else{
// start from the right end of the queue
for(i = itemCount - 1; i >= 0; i-- ){
// if data is larger, shift existing item to right end
if(data > intArray[i]){
intArray[i+1] = intArray[i];
}else{
break;
}
}
// insert the data
intArray[i+1] = data;
itemCount++;
}
}
}
Remove / Dequeue Operation
Whenever an element is to be removed from queue, queue get the element using item count. Once
element is removed. Item count is reduced by one.

int removeData(){
return intArray[--itemCount];
}

You might also like