Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 21

MODULE 3 LECTURE NOTES

Module 3: Stack and Queue


Unit 1: Stack and ADT Stack
Unit 2: Implementation of Stack
Unit 3: Applications of Stack
Unit 4: Stack Expression Manipulation (Pre-fix, In-fix, Post-fix)
Unit 5: Queue and ADT Queue
Unit 6: Implementations of a Queue
Unit 7: Priority Queue and Its Implementation
Unit 8: Applications of Queue

Unit 1: Stack and ADT Stack


A stack is an Abstract Data Type (ADT), with a bounded (predefined)
capacity that is popularly used in most programming languages.

An Abstract Data Type (ADT) is a high-level description of a set of operations


that can be performed on a particular data structure, without specifying the
underlying implementation details. It defines the behavior of the data type
rather than its implementation. The focus is on what operations can be
performed on the data and what properties these operations should have.

In other words, an ADT provides a blueprint for designing and implementing


data structures by specifying the operations that can be performed on the
data, their input parameters, and the expected behavior. It abstracts away
the details of how these operations are implemented, allowing developers to
use the data type without needing to understand the internal workings.

The idea is that the abstract data type provides a clear interface to interact
with the data structure, and users of the ADT are concerned only with how
to use it, not how it is implemented. This separation of concerns helps in
designing modular and maintainable software systems. The actual
implementation of the data type can vary, and different implementations
may provide different trade-offs in terms of efficiency, memory usage, etc.

Data type is a classification of the type of value a variable can hold, a data structure is a
way of organizing and storing data to perform operations efficiently. Data structures
often involve the use of multiple data types to represent complex relationships and

1
hierarchies. While ADTs focus on the abstract behavior of data types, and data structures
focus on their concrete implementation, both share the goal of efficiently organizing
and manipulating data in a way that is understandable and manageable for software
developers.

It is named stack because it has the similar operations as the real-world


stacks, for example – a pack of cards or a pile of plates, etc. Stack can be
regarded as a container in which insertion and deletion can be done from the
one end known as the top of the stack. A Stack is a linear data structure that
follows the LIFO (Last
In First Out) or FILO (First In Last Out) principle, where the last element
inserted would be the first element deleted. A Stack ADT allows all data
operations at one end only. At any given time, we can only access the top
element of a stack.

The following diagram depicts a stack and its operations –

2
A stack can be implemented by means of Array,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.

Working Principles of Stack/ Basic operations of a stack

The most fundamental operations in the stack ADT include: push(), pop(),
peek(), isFull(), isEmpty(). These are all built-in operations to carry out data
manipulation and to check the status of the stack. Stack uses pointers that always
point to the topmost element within the stack, hence called as the top pointer.

Push operation means Inserting a new element into the stack

Pop operation means Removing or deleting elements from the stack

Peek or Top operation refers to retrieving the topmost element in the stack
without removing it from the collections of data items (the stack remains
unchanged).

isFull operation means to check if the stack is full

isEmpty operation means to check if the stack is empty

3
ADT Stack

•Initialize (S): Initialize Stack S

•Push (a, S): Insert item a at the top of stack S. If stack is full, then overflow
occurs.

•Pop (S): Delete or remove item a at the top of stack S. if stack is empty, then
underflows occurs.

•Top (S) or Peek (s): return the item at the top of stack S without changing the
stack

•IsFull(S): return true if stack S is full otherwise false

•size (S): returns the number of items in the stack S.

•IsEmpty(S): return true if stack S is empty otherwise false

Insertion: push()

push() is an operation that inserts elements into the stack. Before inserting an item
into a stack, check if the stack is full. If the stack is full, insertion cannot be done
else overflow condition will occur.

After initializing a stack, the value of top is set to -1 to check that the stack is
empty.

•If a new item is pushed in a stack, the value of the top gets increased by 1 unit,
i.e., top=top+1,(-1+1=0) and the item will be placed at the new position of the
top.

•Items can be pushed until the max size of the stack is reached.

4
The following is an algorithm that describes the push() operation of stack using
array in a simpler way.

1. Checks if the stack is full.


2 − If the stack is full, produces an error and exit.
3 − If the stack is not full, increments top to point next empty space.
4 − Adds data element to the stack location, where top is pointing.
5 − Returns success.

5
Deletion: Pop()

•Before deleting an item from a stack, check if the stack is empty. If the stack is
empty, deletion cannot be done else underflow condition will occur.

•If stack is not empty, the item pointed to by Top is accessed

•If an item is popped from a stack, the value of the top gets decreased by 1 unit,
i.e., top=top-1(3-1=2).

•Items can be popped until the stack is empty.

Deletion: pop()

pop() is a data manipulation operation which removes elements from the stack. The
following Algorithm describes the pop() operation in a simpler way.

Algorithm

6
1 − Checks if the stack is empty.

2 − If the stack is empty, produces an error and exit.

3 − If the stack is not empty, accesses the data element at which top is pointing.

4 − Decreases the value of top by 1.

5 − Returns success.

peek() operation

The peek() is an operation that retrieves the topmost element within the stack,
without deleting it. This operation is used to check the status of the stack with the
help of the top pointer.

Algorithm

1. START

2. return the element at the top of the stack

3. END

isFull() operation

isFull() operation checks whether the stack is full. This operation is used to check
the status of the stack with the help of top pointer.

Algorithm

1. START

2. If the size of the stack is equal to the top position of the stack, the stack is full.
Return 1.

3. Otherwise, return 0.

4. END

isEmpty() operation

The isEmpty() operation verifies whether the stack is empty. This operation is used
to check the status of the stack with the help of top pointer.

Algorithm

1. START
2. If the top value is -1, the stack is empty. Return 1.
3. Otherwise, return 0.

7
4. END

Advantages of Array Implementation of Stack

•Simple implementation • Relatively less memory required for implementation.

Disadvantages of Array Implementation of Stack

• Only contiguous memory allowed • Static structure and size of the stack must be
declared ahead

Linked List Implementation of Stack

• In this implementation, each component in the stack has a pointer part that
points to the next component on the stack.

8
Advantages of Linked List Implementation of Stack

• Dynamic structure implementation •More realistic and implementable in real life

Disadvantages of Linked List Implementation of Stack

• Requires extra memory for pointer

Applications of Stack

•Procedure handling • Evaluation of expression • Data reversal • Backtracking

•Syntax checking • Memory management

Procedure handling: To manage procedure or function calls, computer usually


utilizes a stack data structure. A stack is used since the returning of control after
procedure or function call is always in reverse order.

9
Function call

Stack status

Data reversal: Due to the LIFO operation mechanism of stack, the reverse order
of data can be generated using a stack data structure. In this case, the data can be
numeric or nonnumeric.

10
Syntax Checking: To perform a syntax checking, the compiler makes use of a
stack. When a compiler translates a source program, it reads the characters one at
a time, and if it finds an opening delimiter it places it on a stack. When a closing
delimiter is found, it pops up the opening delimiter from the top of the Stack and
matches it with the closing delimiter otherwise error message will be displayed.

Backtracking: Backtracking is a technique based on algorithm to solve


optimization problems. It uses recursive calling to find the solution by building a
solution step by step increasing values with time. It removes the solutions that
doesn't give rise to the solution of the problem based on the constraints given to
solve the problem. It can use the stack structure to keep the state of the solutions.
It is commonly used in the Maze problem, N Queen problem.

Memory Management: The stack can be used for memory management. The
memory is assigned in the contiguous memory blocks. The memory is known as
stack memory as all the variables are assigned in a function call stack memory. The
memory size assigned to the program is known to the compiler. When the function
is created, all its variables are assigned in the stack memory. When the function
completed its execution, all the variables assigned in the stack are released.

Evaluation of Arithmetic Expression: A stack is a very effective data structure


for evaluating arithmetic expressions in programming languages. An arithmetic
expression consists of operands, operators, and may also contain parentheses or
brackets.

The way to write arithmetic expression is known as a notation. An arithmetic


expression can be written in three different but equivalent notations, i.e., without
changing the essence or output of an expression. These notations are −

• Infix Notation

• Prefix (Polish) Notation

• Postfix (Reverse-Polish) Notation

These notations are named as how they use operator in expression.

The infix notation in most cases requires brackets or arrangement (precedence)


of its operators and it is convenient for human usage. We write expression in infix
notation, e.g. a - b + c, where operators are used in-between operands. It is easy
for us humans to read, write, and speak in infix notation but the same does not go
well with computing devices. An algorithm to process infix notation could be difficult
and costly in terms of time and space consumption.

The pre fix in this notation, operator is prefixed to operands, i.e. operator is
written ahead of operands. For example, +ab. This is equivalent to its infix notation
a + b. Prefix notation is also known as Polish Notation. The notations do not
require arrangements and more applicable for computer evaluation.

11
Post fix: This notation style is known as Reversed Polish Notation. In this
notation style, the operator is postfixed to the operands i.e., the operator is written
after the operands. For example, ab+. This is equivalent to its infix notation a + b.
This notation do not require arrangements and more applicable for computer
evaluation

• Stack is the ideal data structure to evaluate the postfix expression because the
top element is always the most recent operand. The next element on the Stack is
the second most recent operand to be operated on.

The following table briefly tries to show the difference in all the three notations

S.No
Infix Notation Prefix Notation Postfix Notation
.

1 a+b +ab ab+

2 (a + b) ∗ c ∗+abc ab+c∗

3 a ∗ (b + c) ∗a+bc abc+∗

4 a/b+c/d +/ab/cd ab/cd/+

5 (a + b) ∗ (c + d) ∗ + a b + c d ab+cd+∗

6 ((a + b) ∗ c) - d -∗+abcd ab+c∗d-

•Arithmetic expressions can be depicted as prefix, infix, or postfix


representation

• The infix notation is a convenient way of writing an expression in which each


operator is placed between the operands.

E.g. 5+3; A*7; A+7 8/6

• The prefix notation places the operator before the operands. This notation was
introduced by the Polish mathematician and hence often referred to as polish
notation. E.g. g.+ 5 3; * A 7;

• The postfix notation places the operator after the operands. This notation is just
the reverse of Polish notation and also known as Reverse Polish notation. E.g. 5 3
+; A 7 *; 3 x y / +

12
• To evaluate a postfix expression, apply the operator to the two operands
immediately preceding the operator and replace the operator and its operands by
the results of the operation and continue scanning.

Procedure for converting infix to post fix expression

• A stack is used to hold the operators encountered in the infix expression during
its scanning as specified as follows:

• Then Push the operator encountered in the infix expression onto the stack 5.
Whenever a right parenthesis is encountered in the infix expression, remove
continuously operators from the stack, and place them in the order of removal in
the postfix expression until a left parenthesis is encountered on the stack. Then
discard both left and right parenthesis.

1. Empty the stack and scan the expression from left to right

2. Whenever an operand is encountered in the infix expression, copy it to the post

fix expression

3. Whenever an operator is encountered in the infix expression, remove


continuously operators from the stack and place them in the order of removal in the
postfix expression until

•The stack is empty OR the operator on the top of the stack has a lower priority
than the operator encountered in the infix expression OR the operator on the top of
the stack is a left parenthesis.

4. Whenever a left parenthesis is encountered in the infix expression, push it onto


the stack

6. When the whole infix expression has been scanned, pop the operators from the
stack and place them in the postfix expression until the stack is empty.

Algorithm for Evaluating Postfix Expressions:**


Write the infix expression in postfix
1. **Initialize an empty stack.**,
2. **Scan the postfix expression from left to right.**
- For each symbol (operand or operator):
- If it is an operand, push it onto the stack.
- If it is an operator, pop the necessary number of operands from the stack, perform the operation,
and push the result back onto the stack.
3. **After scanning the entire expression, the result will be on the top of the stack. Pop it to get the
final result.**

13
Example 1: 3+4*5
Let's consider the postfix expression `3 4 5 * +`.

1. **Initialize an empty stack:** `Stack = []`


2. **Scan the expression:**
- `3`: Push onto the stack. Stack = `[3]`
- `4`: Push onto the stack. Stack = `[3, 4]`
- `5`: Push onto the stack. Stack = `[3, 4, 5]`
- `*`: Pop two operands (`4` and `5`), perform the operation “*” on them, [`4 * 5], and push the
result (`20`) back onto the stack. Stack = `[3, 20]`
- `+`: Pop two operands (`3` and `20`), perform the operation “+” on them [3 + 20], and push the
result (`23`) back onto the stack. Stack = `[23]`
3. **Result:** The final result is `23`, which is on the top of the stack.

Example 1: Convert (a-b) * (d + e); infix expression to postfix expression

Postfix operation ab-de+*

1. Empty stack : []
2. Push 'a' onto the stack. Stack: [a]
3. Push 'b' onto the stack. Stack: [a, b]
4. Pop 'a' and 'b', then perform the operation “-“, push the result of (a - b) onto the
stack. Stack: [a-b]
5. Push 'd' onto the stack. Stack: [a-b, d]
6. Push 'e' onto the stack. Stack: [a-b, d, e]
7. Pop 'd' and 'e', then perform the operation “+”, push the result of (d + e) onto
the stack. Stack: [a-b, (d+e)]
8. Pop '(d+e)' and 'a-b', perform the operation “*”, push the result of (a-b)*(d+e)
onto the stack. Stack: [(a-b)*(d+e)]

Example 3: Convert 50 * (15+3) -12 infix expression to postfix expression

Postfix operation – 50 15 3 +* 12 -

1. Empty stack : []
2. Push '50' onto the stack. Stack: [50]
3. Push '15' onto the stack. Stack: [50, 15]
4. Push '3' onto the stack. Stack: [50, 15, 3]

14
5. Pop '3' and '15', perform the operation “+” then push the result of [ 15+3] onto
the stack. Stack: [50, 18]
6. Pop '18' and '50', perform the operation “*” then push the result of [ 50×18] onto
the stack. Stack: [900]
7. Push '12' onto the stack. Stack: [900, 12]
8. Pop '900' and '12', perform the operation “-“ then push the result of [ 900−12]
onto the stack. Stack: [888]

At this point, the stack contains the result of the postfix expression, which is
50×(15+3)−12=888.

Advantages of Stack

• Stacks can be used for systematic Memory Management.

• It is used in many virtual machines like JVM.

• Stacks are more secure and reliable as they do not get corrupted easily

• Stack allows control over memory allocation and deallocation.

Disadvantages of Stack

• Stack memory is of limited size.

• If too many objects are created, then it can lead to stack overflow.

• Random accessing is not possible in stack.

• If the stack falls outside the memory it can lead to abnormal termination.

Queue Data Structure

Queue can be regarded as a structure in which there can be insertion from one end
called rear and deletion from another end known as the rear.

•Items in a queue are accessed in the order of their insertion

•A Queue is a linear data structure that follows the FIFO (First In First Out) or the
LILO (Last In Last Out) principle.

• Queue is an abstract data type with a bounded (predefined) capacity.

Queue, like Stack, is also an abstract data structure. The thing that makes queue
different from stack is that a queue is open at both its ends. Hence, it follows FIFO

15
(First-In-First-Out) structure, i.e. the data item inserted first will also be accessed
first. The data is inserted into the queue through one end and deleted from it using
the other end.

Similar to the stack ADT, a queue ADT can also be implemented using arrays,
linked lists, or pointers. As a simple example, we will implement queues using a
one-dimensional array.

Basic Operations/Working Principles of Queue

• Inserting a new element into the queue is termed an enqueue operation.

• Removing or deleting elements from the queue is termed a dequeue operation.

ADT Queue

Initialize (Q): Initialize Queue Q

Enqueue (a, Q): Insert item a at the rear of the queue Q.

Dequeue (Q): Insert item a at the rear of the queue Q.

16
Front (Q): returns the item at the front of queue Q without changing the queue
provided queue is not empty.

rear (Q): returns the item at the rear of queue Q without changing the queue
provided queue is not empty.

IsEmpty(Q): return true if queue Q is empty otherwise false

IsFull(Q): return true if queue Q is full otherwise false

size(Q): returns the number of items in the Queue Q.

The most fundamental operations in the queue ADT include: enqueue(), dequeue(),
peek(), isFull(), isEmpty(). These are all built-in operations to carry out data
manipulation and to check the status of the queue.

Queue uses two pointers − front and rear. The front pointer accesses the data from
the front end (helping in enqueueing) while the rear pointer accesses data from the
rear end (helping in dequeuing).

Insertion operation: enqueue()

The enqueue() is a data manipulation operation that is used to insert elements into
the queue. The following algorithm describes the enqueue() operation in a simpler
way.

Algorithm

1 − START

2 – Check if the queue is full.

3 − If the queue is full, produce overflow error and exit.

4 − If the queue is not full, increment rear pointer to point the next empty space.

5 − Add data element to the queue location, where the rear is pointing.

6 − return success.

7 – END

17
Deletion Operation: dequeue()

The dequeue() is a data manipulation operation that is used to remove elements


from the queue. Dequeue() operation in Queue removes (or delete) the first
element on the queue. The following algorithm describes the dequeue() operation in
a simpler way.

Algorithm

1 – START

2 − Check if the queue is empty.

3 − If the queue is empty, produce underflow error and exit.

4 − If the queue is not empty, access the data where front is pointing.

5 − Increment front pointer to point to the next available data element.

6 − Return success.

7 – END

18
Implementations of Queue : Array Implementation of Queue

In this implementation, a linear array and two pointers are used. The linear array
contains the items while the two pointers to the front (first element) and the rear
(last item) respectively in the array.

Advantages of Array Implementation of Queue

19
• Easy implementation • Enqueue and dequeue are easy to implement

Disadvantages of Array Implementation of Queue

• Only contiguous memory allowed • Static structure and size of the queue must be
declared ahead

Types of Queue

• Simple queue also known as a linear queue is the most basic version of a queue.
Here, insertion of an element i.e. the Enqueue operation takes place at the rear end
and removal of an element i.e. the Dequeue operation takes place at the front end

Circular Queue: In a circular queue, the element of the queue act as a circular
ring. The working of a circular queue is similar to the linear queue except for the
fact that the last element is connected to the first element. Its advantage is that
the memory is utilized in a better way. This is because if there is an empty space
i.e. if no element is present at a certain position in the queue, then an element can
be easily added at that position.

Priority Queue: This queue is a special type of queue. Its specialty is that it
arranges the elements in a queue based on some priority. The priority can be
something where the element with the highest value has the priority so it creates a
queue with decreasing order of values. The priority can also be such that the
element with the lowest value gets the highest priority so in turn it creates a queue
with increasing order of values.

DEqueue: Dequeue is also known as Double Ended Queue. As the name suggests
double ended, it means that an element can be inserted or removed from both the
ends of the queue unlike the other queues in which it can be done only from one
end. Because of this property it may not obey the First In First Out property.

Applications of Queue

• Multi programming means when multiple programs are running in the main
memory. It is essential to organize these multiple programs and these multiple
programs are organized as queues.

Multiprogramming Network: In a network, a queue is used in devices such as a


router or a switch. another application of a queue is a mail queue which is a
directory that stores data and controls files for mail messages.

Job Scheduling: The computer has a task to execute a particular number of jobs
that are scheduled to be executed one after another. These jobs are assigned to the
processor one by one which is organized using a queue

Shared Resources: Queues are used as waiting lists for a single shared resource.

20
Advantages of Queue

A large amount of data can be managed efficiently with ease

Operations such as insertion and deletion can be performed with ease as it follows
the first in first out rule.

Queues are useful when a particular service is used by multiple consumers.

Queues are fast in speed for data inter-process communication.

Queues can be used in the implementation of other data structures.

Disadvantages of Queue
The operations such as insertion and deletion of elements from the middle are time
consuming.

In a classical queue, a new element can only be inserted when the existing
elements are deleted from the queue.

21

You might also like