UNIT II
Stack ADT-Operations- Applications- Evaluating arithmetic expressions –
Conversion of infix topostfix expression-Queue ADT-Operations-Circular Queue-
Priority Queue- deQueueapplications of queues.
What is a Stack?
Stack is a linear data structure in which the insertion and deletion operations are
performed at only one end. In a stack, adding and removing of elements are
performed at a single position which is known as "top". That means, a new element
is added at top of the stack and an element is removed from the top of the stack. In
stack, the insertion and deletion operations are performed based on LIFO (Last In
First Out) principle.
In a stack, the insertion operation is performed using a function called "push" and
deletion operation is performed using a function called "pop".
In the figure, PUSH and POP operations are performed at a top position in the stack.
That means, both the insertion and deletion operations are performed at one end (i.e.,
at Top)
A stack data structure can be defined as follows...
Stack is a linear data structure in which the operations are performed based on
LIFO principle.
Stack can also be defined as
"A Collection of similar data items in which both insertion and deletion
operations are performed based on LIFO principle".
Example
If we want to create a stack by inserting 10,45,12,16,35 and 50. Then 10 becomes the
bottom-most element and 50 is the topmost element. The last inserted element 50 is
at Top of the stack as shown in the image below...
Operations on a Stack
The following operations are performed on the stack...
1. Push (To insert an element on to the stack)
2. Pop (To delete an element from the stack)
3. Display (To display elements of the stack)
Stack data structure can be implemented in two ways. They are as follows...
1. Using Array
2. Using Linked List
When a stack is implemented using an array, that stack can organize an only limited
number of elements. When a stack is implemented using a linked list, that stack can
organize an unlimited number of elements.
Stack Using Array
A stack data structure can be implemented using a one-dimensional array. But stack
implemented using array stores only a fixed number of data values. This
implementation is very simple. Just define a one dimensional array of specific size
and insert or delete the values into that array by using LIFO principle with the help
of a variable called 'top'. Initially, the top is set to -1. Whenever we want to insert a
value into the stack, increment the top value by one and then insert. Whenever we
want to delete a value from the stack, then delete the top value and decrement the top
value by one.
Stack Operations using Array
A stack can be implemented using array as follows...
Before implementing actual operations, first follow the below steps to create an
empty stack.
Step 1 - Include all the header files which are used in the program and define
a constant 'SIZE' with specific value.
Step 2 - Declare all the functions used in stack implementation.
Step 3 - Create a one dimensional array with fixed size (int stack[SIZE])
Step 4 - Define a integer variable 'top' and initialize with '-1'. (int top = -1)
Step 5 - In main method, display menu with list of operations and make
suitable function calls to perform operation selected by the user on the stack.
push(value) - Inserting value into the stack
In a stack, push() is a function used to insert an element into the stack. In a stack, the
new element is always inserted at top position. Push function takes one integer value
as parameter and inserts that value into the stack. We can use the following steps to
push an element on to the stack...
Step 1 - Check whether stack is FULL. (top == SIZE-1)
Step 2 - If it is FULL, then display "Stack is FULL!!! Insertion is not
possible!!!" and terminate the function.
Step 3 - If it is NOT FULL, then increment top value by one (top++) and set
stack[top] to value (stack[top] = value).
pop() - Delete a value from the Stack
In a stack, pop() is a function used to delete an element from the stack. In a stack, the
element is always deleted from top position. Pop function does not take any value as
parameter. We can use the following steps to pop an element from the stack...
Step 1 - Check whether stack is EMPTY. (top == -1)
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 delete stack[top] and decrement top value
by one (top--).
display() - 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'.
Stack Using Linked List
The major problem with the stack implemented using an array is, it works only for a
fixed number of data values. That means the amount of data must be specified at the
beginning of the implementation itself. Stack implemented using an array is not
suitable, when we don't know the size of data which we are going to use. A stack data
structure can be implemented by using a linked list data structure. The stack
implemented using linked list can work for an unlimited number of values. That
means, stack implemented using linked list works for the variable size of data. So,
there is no need to fix the size at the beginning of the implementation. The Stack
implemented using linked list can organize as many data values as we want.
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
In the above example, 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
To implement a stack using a linked list, we need to set the following things before
implementing actual operations.
Step 1 - Include all the header files which are used in the program. And
declare all the user defined functions.
Step 2 - Define a 'Node' structure with two members data and next.
Step 3 - Define a Node pointer 'top' and set it to NULL.
Step 4 - Implement the main method by displaying Menu with list of
operations and make suitable function calls in the main method.
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.
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)).
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'.
Applications of Stack in Data Structure:
o Evaluation of Arithmetic Expressions
o Backtracking
o Delimiter Checking
o Reverse a Data
o Processing Function Calls
1. Evaluation of Arithmetic Expressions
A stack is a very effective data structure for evaluating arithmetic expressions in
programming languages. An arithmetic expression consists of operands and
operators.
In addition to operands and operators, the arithmetic expression may also include
parenthesis like "left parenthesis" and "right parenthesis".
Example: A + (B - C)
To evaluate the expressions, one needs to be aware of the standard precedence rules for arithmetic
expression. The precedence rules for the five basic arithmetic operators are:
Operators Associativit Precedence
y
^ exponentiation Right to left Highest followed by *Multiplication and
/division
*Multiplication, Left to right Highest followed by + addition and -
/division subtraction
+ addition, - Left to right lowest
subtraction
Evaluation of Arithmetic Expression requires two steps:
o First, convert the given expression into special notation.
o Evaluate the expression in this new notation.
Notations for Arithmetic Expression
There are three notations to represent an arithmetic expression:
o Infix Notation
o Prefix Notation
o Postfix Notation
Infix Notation
The infix notation is a convenient way of writing an expression in which each
operator is placed between the operands. Infix expressions can be parenthesized or
unparenthesized depending upon the problem requirement.
Example: A + B, (C - D) etc.
All these expressions are in infix notation because the operator comes between the
operands.
Prefix Notation
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.
Example: + A B, -CD etc.
All these expressions are in prefix notation because the operator comes before the
operands.
Postfix Notation
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.
Example: AB +, CD+, etc.
All these expressions are in postfix notation because the operator comes after the
operands.
Conversion of Arithmetic Expression into various Notations:
Any expression can be represented using three types of expressions (Infix, Postfix,
and Prefix). We can also convert one type of expression to another type of expression
like Infix to Postfix, Infix to Prefix, Postfix to Prefix and vice versa.
To convert any Infix expression into Postfix or Prefix expression we can use the
following procedure...
1. Find all the operators in the given Infix Expression.
2. Find the order of operators evaluated according to their Operator precedence.
3. Convert each operator into required type of expression (Postfix or Prefix) in
the same order.
Example
Consider the following Infix Expression to be converted into Postfix Expression...
D=A+B*C
Step 1 - The Operators in the given Infix Expression : = , + , *
Step 2 - The Order of Operators according to their preference : * , + , =
Step 3 - Now, convert the first operator * ----- D = A + B C *
Step 4 - Convert the next operator + ----- D = A BC* +
Step 5 - Convert the next operator = ----- D ABC*+ =
Finally, given Infix Expression is converted into Postfix Expression as follows...
DABC*+=
Infix to Postfix Conversion using Stack Data Structure
To convert Infix Expression into Postfix Expression using a stack data structure, We
can use the following steps...
1. Read all the symbols one by one from left to right in the given Infix
Expression.
2. If the reading symbol is operand, then directly print it to the result (Output).
3. If the reading symbol is left parenthesis '(', then Push it on to the Stack.
4. If the reading symbol is right parenthesis ')', then Pop all the contents of stack
until respective left parenthesis is poped and print each poped symbol to the
result.
5. If the reading symbol is operator (+ , - , * , / etc.,), then Push it on to the Stack.
However, first pop the operators which are already on the stack that have
higher or equal precedence than current operator and print them to the result.
Example
Consider the following Infix Expression...
(A+B)*(C-D)
The given infix expression can be converted into postfix expression using Stack data
Structure as follows...
The final Postfix Expression is as follows...
AB+CD-*
Postfix Expression Evaluation using Stack Data Structure
A postfix expression can be evaluated using the Stack data structure. To evaluate a
postfix expression using Stack data structure we can use the following steps...
1. Read all the symbols one by one from left to right in the given Postfix
Expression
2. If the reading symbol is operand, then push it on to the Stack.
3. If the reading symbol is operator (+ , - , * , / etc.,), then perform TWO pop
operations and store the two popped oparands in two different variables
(operand1 and operand2). Then perform reading symbol operation using
operand1 and operand2 and push result back on to the Stack.
4. Finally! perform a pop operation and display the popped value as final result.
Example
Consider the following Expression...
Queue ADT
What is a Queue?
Queue is a linear data structure in which the insertion and deletion operations are
performed at two different ends. In a queue data structure, adding and removing
elements are performed at two different positions. The insertion is performed at one
end and deletion is performed at another end. In a queue data structure, the insertion
operation is performed at a position which is known as 'rear' and the deletion
operation is performed at a position which is known as 'front'. In queue data
structure, the insertion and deletion operations are performed based on FIFO (First
In First Out) principle.
In a queue data structure, the insertion operation is performed using a function called
"enQueue()" and deletion operation is performed using a function called
"deQueue()".
Queue data structure can be defined as follows...
Queue data structure is a linear data structure in which the operations are
performed based on FIFO principle.
A queue data structure can also be defined as
"Queue data structure is a collection of similar data items in which insertion
and deletion operations are performed based on FIFO principle".
Example
Queue after inserting 25, 30, 51, 60 and 85.
Operations on a Queue
The following operations are performed on a queue data structure...
1. enQueue(value) - (To insert an element into the queue)
2. deQueue() - (To delete an element from the queue)
3. display() - (To display the elements of the queue)
Queue data structure can be implemented in two ways. They are as follows...
1. Using Array
2. Using Linked List
When a queue is implemented using an array, that queue can organize an only limited
number of elements. When a queue is implemented using a linked list, that queue can
organize an unlimited number of elements.
Queue Datastructure Using Array
A queue data structure can be implemented using one dimensional array. The queue
implemented using array stores only fixed number of data values. The
implementation of queue data structure using array is very simple. Just define a one
dimensional array of specific size and insert or delete the values into that array by
using FIFO (First In First Out) principle with the help of variables 'front' and
'rear'. Initially both 'front' and 'rear' are set to -1. Whenever, we want to insert a new
value into the queue, increment 'rear' value by one and then insert at that position.
Whenever we want to delete a value from the queue, then delete the element which is
at 'front' position and increment 'front' value by one.
Queue Operations using Array
Queue data structure using array can be implemented as follows...
Before we implement actual operations, first follow the below steps to create an
empty queue.
Step 1 - Include all the header files which are used in the program and define
a constant 'SIZE' with specific value.
Step 2 - Declare all the user defined functions which are used in queue
implementation.
Step 3 - Create a one dimensional array with above defined SIZE (int
queue[SIZE])
Step 4 - Define two integer variables 'front' and 'rear' and initialize both
with '-1'. (int front = -1, rear = -1)
Step 5 - Then implement main method by displaying menu of operations list
and make suitable function calls to perform operation selected by the user on
queue.
enQueue(value) - Inserting value into the queue
In a queue data structure, enQueue() is a function used to insert a new element into
the queue. In a queue, the new element is always inserted at rear position. The
enQueue() function takes one integer value as a parameter and inserts that value into
the queue. We can use the following steps to insert an element into the queue...
Step 1 - Check whether queue is FULL. (rear == SIZE-1)
Step 2 - If it is FULL, then display "Queue is FULL!!! Insertion is not
possible!!!" and terminate the function.
Step 3 - If it is NOT FULL, then increment rear value by one (rear++) and
set queue[rear] = value.
deQueue() - Deleting a value from the Queue
In a queue data structure, deQueue() is a function used to delete an element from the
queue. In a queue, the element is always deleted from front position. The deQueue()
function does not take any value as parameter. We can use the following steps to
delete an element from the queue...
Step 1 - Check whether queue is EMPTY. (front == rear)
Step 2 - If it is EMPTY, then display "Queue is EMPTY!!! Deletion is not
possible!!!" and terminate the function.
Step 3 - If it is NOT EMPTY, then increment the front value by one (front +
+). Then display queue[front] as deleted element. Then check whether
both front and rear are equal (front == rear), if it TRUE, then set
both front and rear to '-1' (front = rear = -1).
display() - Displays the elements of a Queue
We can use the following steps to display the elements of a queue...
Step 1 - Check whether queue is EMPTY. (front == rear)
Step 2 - If it is EMPTY, then display "Queue is EMPTY!!!" and terminate
the function.
Step 3 - If it is NOT EMPTY, then define an integer variable 'i' and set
'i = front+1'.
Step 4 - Display 'queue[i]' value and increment 'i' value by one (i++). Repeat
the same until 'i' value reaches to rear (i <= rear)
Queue Using Linked List
The major problem with the queue implemented using an array is, It will work for an
only fixed number of data values. That means, the amount of data must be specified
at the beginning itself. Queue using an array is not suitable when we don't know the
size of data which we are going to use. A queue data structure can be implemented
using a linked list data structure. The queue which is implemented using a linked list
can work for an unlimited number of values. That means, queue using linked list can
work for the variable size of data (No need to fix the size at the beginning of the
implementation). The Queue implemented using linked list can organize as many
data values as we want.
In linked list implementation of a queue, the last inserted node is always pointed by
'rear' and the first node is always pointed by 'front'.
Example
In above example, the last inserted node is 50 and it is pointed by 'rear' and the first
inserted node is 10 and it is pointed by 'front'. The order of elements inserted is 10,
15, 22 and 50.
Operations
To implement queue using linked list, we need to set the following things before
implementing actual operations.
Step 1 - Include all the header files which are used in the program. And
declare all the user defined functions.
Step 2 - Define a 'Node' structure with two members data and next.
Step 3 - Define two Node pointers 'front' and 'rear' and set both to NULL.
Step 4 - Implement the main method by displaying Menu of list of operations
and make suitable function calls in the main method to perform user selected
operation.
enQueue(value) - Inserting an element into the Queue
We can use the following steps to insert a new node into the queue...
Step 1 - Create a newNode with given value and set 'newNode → next'
to NULL.
Step 2 - Check whether queue is Empty (rear == NULL)
Step 3 - If it is Empty then, set front = newNode and rear = newNode.
Step 4 - If it is Not Empty then, set rear →
next = newNode and rear = newNode.
deQueue() - Deleting an Element from Queue
We can use the following steps to delete a node from the queue...
Step 1 - Check whether queue is Empty (front == NULL).
Step 2 - If it is Empty, then display "Queue is Empty!!! Deletion is not
possible!!!" and terminate from the function
Step 3 - If it is Not Empty then, define a Node pointer 'temp' and set it to
'front'.
Step 4 - Then set 'front = front → next' and delete 'temp' (free(temp)).
display() - Displaying the elements of Queue
We can use the following steps to display the elements (nodes) of a queue...
Step 1 - Check whether queue is Empty (front == NULL).
Step 2 - If it is Empty then, display 'Queue is Empty!!!' and terminate the
function.
Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize
with front.
Step 4 - Display 'temp → data --->' and move it to the next node. Repeat the
same until 'temp' reaches to 'rear' (temp → next != NULL).
Step 5 - Finally! Display 'temp → data ---> NULL'.
Circular Queue Datastructure
In a normal Queue Data Structure, we can insert elements until queue becomes full.
But once the queue becomes full, we can not insert the next element until all the
elements are deleted from the queue. For example, consider the queue below...
The queue after inserting all the elements into it is as follows...
Now consider the following situation after deleting three elements from the queue...
This situation also says that Queue is Full and we cannot insert the new element
because 'rear' is still at last position. In the above situation, even though we have
empty positions in the queue we can not make use of them to insert the new element.
This is the major problem in a normal queue data structure. To overcome this
problem we use a circular queue data structure.
What is Circular Queue?
A Circular Queue can be defined as follows...
A circular queue is a linear data structure in which the operations are
performed based on FIFO (First In First Out) principle and the last position is
connected back to the first position to make a circle.
Graphical representation of a circular queue is as follows...
Implementation of Circular Queue
To implement a circular queue data structure using an array, we first perform the
following steps before we implement actual operations.
Step 1 - Include all the header files which are used in the program and define
a constant 'SIZE' with specific value.
Step 2 - Declare all user defined functions used in circular queue
implementation.
Step 3 - Create a one dimensional array with above defined SIZE (int
cQueue[SIZE])
Step 4 - Define two integer variables 'front' and 'rear' and initialize both
with '-1'. (int front = -1, rear = -1)
Step 5 - Implement main method by displaying menu of operations list and
make suitable function calls to perform operation selected by the user on
circular queue.
enQueue(value) - Inserting value into the Circular Queue
In a circular queue, enQueue() is a function which is used to insert an element into
the circular queue. In a circular queue, the new element is always inserted
at rear position. The enQueue() function takes one integer value as parameter and
inserts that value into the circular queue. We can use the following steps to insert an
element into the circular queue...
Step 1 - Check whether queue is FULL. ((rear == SIZE-1 && front == 0) ||
(front == rear+1))
Step 2 - If it is FULL, then display "Queue is FULL!!! Insertion is not
possible!!!" and terminate the function.
Step 3 - If it is NOT FULL, then check rear == SIZE - 1 && front != 0 if it
is TRUE, then set rear = -1.
Step 4 - Increment rear value by one (rear++), set queue[rear] = value and
check 'front == -1' if it is TRUE, then set front = 0.
deQueue() - Deleting a value from the Circular Queue
In a circular queue, deQueue() is a function used to delete an element from the
circular queue. In a circular queue, the element is always deleted from front position.
The deQueue() function doesn't take any value as a parameter. We can use the
following steps to delete an element from the circular queue...
Step 1 - Check whether queue is EMPTY. (front == -1 && rear == -1)
Step 2 - If it is EMPTY, then display "Queue is EMPTY!!! Deletion is not
possible!!!" and terminate the function.
Step 3 - If it is NOT EMPTY, then display queue[front] as deleted element
and increment the front value by one (front ++). Then check whether front
== SIZE, if it is TRUE, then set front = 0. Then check whether both front -
1 and rear are equal (front -1 == rear), if it TRUE, then set
both front and rear to '-1' (front = rear = -1).
display() - Displays the elements of a Circular Queue
We can use the following steps to display the elements of a circular queue...
Step 1 - Check whether queue is EMPTY. (front == -1)
Step 2 - If it is EMPTY, then display "Queue is EMPTY!!!" and terminate
the function.
Step 3 - If it is NOT EMPTY, then define an integer variable 'i' and set
'i = front'.
Step 4 - Check whether 'front <= rear', if it is TRUE, then display 'queue[i]'
value and increment 'i' value by one (i++). Repeat the same until 'i <= rear'
becomes FALSE.
Step 5 - If 'front <= rear' is FALSE, then display 'queue[i]' value and
increment 'i' value by one (i++). Repeat the same until'i <= SIZE - 1'
becomes FALSE.
Step 6 - Set i to 0.
Step 7 - Again display 'cQueue[i]' value and increment i value by one (i++).
Repeat the same until 'i <= rear' becomes FALSE.
Double Ended Queue Datastructure
Double Ended Queue is also a Queue data structure in which the insertion and
deletion operations are performed at both the ends (front and rear). That means, we
can insert at both front and rear positions and can delete from both front and rear
positions.
Double Ended Queue can be represented in TWO ways, those are as follows...
1. Input Restricted Double Ended Queue
2. Output Restricted Double Ended Queue
Input Restricted Double Ended Queue
In input restricted double-ended queue, the insertion operation is performed at only
one end and deletion operation is performed at both the ends.
Output Restricted Double Ended Queue
In output restricted double ended queue, the deletion operation is performed at only
one end and insertion operation is performed at both the ends.
What is a priority queue?
A priority queue is an abstract data type that behaves similarly to the normal queue
except that each element has some priority, i.e., the element with the highest priority
would come first in a priority queue. The priority of the elements in a priority queue
will determine the order in which elements are removed from the priority queue.
The priority queue supports only comparable elements, which means that the
elements are either arranged in an ascending or descending order.
For example, suppose we have some values like 1, 3, 4, 8, 14, 22 inserted in a
priority queue with an ordering imposed on the values is from least to the greatest.
Therefore, the 1 number would be having the highest priority while 22 will be having
the lowest priority.
Characteristics of a Priority queue
A priority queue is an extension of a queue that contains the following
characteristics:
o Every element in a priority queue has some priority associated with it.
o An element with the higher priority will be deleted before the deletion of the
lesser priority.
o If two elements in a priority queue have the same priority, they will be
arranged using the FIFO principle.
Types of Priority Queue
There are two types of priority queue:
o Ascending order priority queue: In ascending order priority queue, a lower
priority number is given as a higher priority in a priority. For example, we take
the numbers from 1 to 5 arranged in an ascending order like 1,2,3,4,5;
therefore, the smallest number, i.e., 1 is given as the highest priority in a
priority queue.
o Descending order priority queue: In descending order priority queue, a
higher priority number is given as a higher priority in a priority. For example,
we take the numbers from 1 to 5 arranged in descending order like 5, 4, 3, 2, 1;
therefore, the largest number, i.e., 5 is given as the highest priority in a priority
queue.
Applications of Queue data structure :
1. Task Scheduling:
Queues can be used to schedule tasks based on priority or the order in which they
were received.
2. Resource Allocation:
Queues can be used to manage and allocate resources, such as printers or CPU
processing time.
3. Batch Processing:
Queues can be used to handle batch processing jobs, such as data analysis or
image rendering.
4. Message Buffering:
Queues can be used to buffer messages in communication systems, such as
message queues in messaging systems or buffers in computer networks.
5. Event Handling:
Queues can be used to handle events in event-driven systems, such as GUI
applications or simulation systems.
6. Traffic Management:
Queues can be used to manage traffic flow in transportation systems, such as
airport control systems or road networks.
7. Operating systems:
Operating systems often use queues to manage processes and resources. For
example, a process scheduler might use a queue to manage the order in which
processes are executed.
8. Network protocols:
Network protocols like TCP and UDP use queues to manage packets that are
transmitted over the network. Queues can help to ensure that packets are delivered
in the correct order and at the appropriate rate.
9. Printer queues :
In printing systems, queues are used to manage the order in which print jobs are
processed. Jobs are added to the queue as they are submitted, and the printer
processes them in the order they were received.
10. Web servers:
Web servers use queues to manage incoming requests from clients. Requests are
added to the queue as they are received, and they are processed by the server in
the order they were received.
11. Breadth-first search algorithm:
The breadth-first search algorithm uses a queue to explore nodes in a graph level-
by-level. The algorithm starts at a given node, adds its neighbors to the queue, and
then processes each neighbor in turn.