CSC312 -- Lecture 3b
CSC312 -- Lecture 3b
Authors
Michael T. Goodrich, Roberto Tamassia, and David M. Mount.
2
Lecture Objective
3
Lecture Outline
4
Introduction
▪ Another fundamental data structure is the queue, which is a close relative of
the stack.
▪ A queue is a container of elements that are inserted and removed according
to the first-in first-out (FIFO) principle.
▪ Elements enter the queue at the rear and are removed from the front
Rear
Front
5
Introduction
6
Introduction
▪ The queue data structure is widely used in various computing scenarios. Here
are some direct and indirect applications of queues:
▪ Direct Applications
▪ Scheduling Tasks in Operating systems
▪ Message Queues in Communication Systems
▪ Real-Time Data Processing
▪ Job/Task Scheduling in Servers
▪ Buffer Management
▪ Indirect applications extend the concept of queues into broader areas like
simulation, concurrency management, networking, and even real-world systems.
7
The Queue Abstract Data Type
▪ Formally, the queue abstract data type defines a container that keeps
elements in a sequence, where
▪ element access and deletion are restricted to the first element in the sequence, which is
called the front of the queue, and
▪ element insertion is restricted to the end of the sequence, which is called the rear of
the queue.
▪ This restriction enforces the rule that items are inserted and deleted in a
queue according to the first-in first-out (FIFO) principle.
8
The Queue Abstract Data Type
▪ The queue abstract data type (ADT) supports the following operations:
Operation Description
enqueue(𝑒) Insert element 𝑒 at the rear of the queue.
dequeue() Remove element at the front of the queue; an error occurs if the
queue is empty.
front() Return, but do not remove, a reference to the front element in the
queue; an error occurs if the queue is empty.
size() Return the number of elements in the queue.
empty() Return true if the queue is empty and false otherwise.
▪ Note: 𝑆𝑖𝑧𝑒() and 𝑒𝑚𝑝𝑡𝑦() are supporting member functions of the queue ADT
9
The Queue ADT Operations
▪ The following table shows a series of queue operations and their effects on an initially
empty queue, 𝑄, of integers
Operation Output 𝒇𝒓𝒐𝒏𝒕 ← 𝑸 ← 𝒓𝒆𝒂𝒓
(Cont’d)
11
Class Exercise 1: Solution
(Cont’d)
Operation Output 𝒇𝒓𝒐𝒏𝒕 ← 𝑸 ← 𝒓𝒆𝒂𝒓
size() 3 (15, 20, 25)
enqueue(5) - (5)
empty() false (15, 20, 25)
enqueue(10) - (5,10)
dequeue() - (20, 25)
front() 5 (5,10)
front() 20 (20, 25)
size() 2 (5, 10)
enqueue(30) - (20, 25, 30)
enqueue(15) - (5, 10, 15)
dequeue() - (25,30)
dequeue() - (10, 15)
enqueue(35) - (25,30,35)
enqueue(20) - (10, 15, 20)
size() 3 (25,30,35)
front() 10 (10, 15, 20)
dequeue() - (30,35)
enqueue(25) - (10, 15, 20, 25)
empty() false (30,35)
dequeue() - (15, 20, 25)
12
The STL Queue
▪ The Standard Template Library provides an implementation of a queue based on
STL vector class.
▪ In order to declare an object of type queue, it is necessary to first include the
definition file, which is called “queue”.
▪ The class queue is part of the std namespace, so it is necessary either to use
“std::queue” or to provide an appropriate “using” statement.
▪ The queue class is templated with the base type of the individual elements. For
example, the code fragment (next slide) declares a queue of floats.
▪ As with instances of STL vectors and stacks, an STL queue dynamically resizes
itself as new elements are added.
13
The STL Queue
▪ Let 𝒒 be declared to be an STL queue, and let 𝒆 denote a single object whose type is the
same as the base type of the queue.
▪ For example, 𝒒 is a queue of floats, and 𝒆 is a float.
Operation Description
#include <queue> push(𝑒) Enqueue 𝑒 at the rear of the queue.
// make queue accessible pop() Dequeue the element at the front of the queue.
using std::queue; front() Return a reference to the element at the queue’s
// a queue of floats front.
queue<float> myQueue; back() Return a reference to the element at the queue’s rear.
size() Return the number of elements in the queue.
empty() Return true if the queue is empty and false otherwise.
14
The STL Queue
▪ The STL queue provides access to both the front and back of the queue.
▪ The result of applying any of the operations front, back, or pop to an empty
STL queue is undefined.
▪ No exception is thrown, but it may very likely result in the program aborting.
▪ Therefore, it is up to the programmer to be sure that no such illegal accesses are
attempted.
15
Queue Interface (using C++ )
▪ An interface implementation for the queue ADT is given in Code Fragment
(next slide)
▪ As with the stack ADT, the class is templated. The queue’s base element type
𝐸 is provided by the user.
▪ Note that the 𝒔𝒊𝒛𝒆 and 𝒆𝒎𝒑𝒕𝒚 functions have the same meaning as their
counterparts in the Stack ADT.
▪ These two member functions and 𝒇𝒓𝒐𝒏𝒕 are known as accessor
functions
▪ because they return a value and do not change the contents of the data structure.
16
template <typename E>
class Queue { // an interface for a queue
public:
int size() const; // number of items in queue
bool empty() const; // is the queue empty?
const E& front() const throw(QueueEmpty); // the front element
void enqueue (const E& e); // enqueue element at rear
void dequeue() throw(QueueEmpty); // dequeue element at front
};
18
Case Study (Queue):
Bank Teller Queue Simulation
19
Case Study (Queue):
Bank Teller Queue Simulation
20
Case Study (Queue):
Bank Teller Queue Simulation
enqueue(𝒙) dequeue() Front() Size() Empty()
When a When the bank The teller can At any moment, Sometimes, there
teller is ready look at the the teller can might be no
customer 𝑥 count how many customers in
arrives at the to serve the front of the people are still line. This
bank, they next line to see waiting in line. operation
join the end customer, who’s next This operation checks if the
of the waiting they take the without tells them the queue is empty,
line. customer at removing total number of letting the teller
customers in the know they’re
the front of anyone from queue. free until the
the line. the queue. next customer
arrives.
21
Class Exercise 2
▪ Consider the following sequence of 20 operations on a bank teller queue.
Operations: enqueue('David’); enqueue(‘Mary’); enqueue('Abraham’);
size(); front(); dequeue(); front(); size(); enqueue(‘Ruth’);
enqueue('Solomon’); empty(); front(); dequeue(); front(); dequeue(); size();
dequeue(); front(); dequeue(); empty()
24
Deque
▪ Analogy for a double-ended queue (deque):
▪ Imagine a line at a popular coffee truck that has two
service windows, one at the front and one at the
back.
▪ Customers can join the line from either end, and
they also have the flexibility to get served from
either window.This allows:
▪ New arrivals to join from the front or the
back, depending on which window they prefer.
▪ Service to occur at both ends, so a customer at
the front or back can receive their order and
leave.
▪ In this analogy, the double-ended queue (deque) is
represented by the flexible, two-way nature of both
entering and exiting the line.
25
Deque
26
The Deque Abstract Data Type
▪ The operations of the deque ADT are as follows, where 𝐷 denotes the
deque:
Operation Description
insertFront(𝑒) Insert a new element 𝑒 at the beginning of the deque.
insertBack(𝑒) Insert a new element 𝑒 at the end of the deque.
eraseFront() Remove the first element of the deque; an error occurs
if the deque is empty.
eraseBack() Remove the last element of the deque; an error occurs if
the deque is empty.
27
The Deque Abstract Data Type
▪ Additionally, the deque includes the following support operations:
Operation Description
front() Return the first element of the deque; an error occurs if
the deque is empty.
back() Return the last element of the deque; an error occurs if
the deque is empty.
size() Return the number of elements of the deque.
empty() Return true if the deque is empty and false otherwise.
28
The Deque ADT Operations
▪ The following example shows a series of operations and their effects on an initially empty
deque, D, of integers.
Operation Output 𝑫
insertFront(3) - (3)
insertFront(5) - (5,3)
front() 5 (5,3)
eraseFront() - (3)
insertBack(7) - (3,7)
Back() 7 (3,7)
eraseFront() - (7)
eraseBack() - ()
29
Class Exercise 3
▪ Consider the following sequence of deque operations. Perform the
operations step-by-step and provide the output for each operation.
Assume the deque holds integers:
▪ Operations Sequence: insertFront(5). insertBack(10),
insertFront(3), insertBack(7), insertFront(1), eraseFront(),
eraseBack(), insertBack(6), front(), back(), insertFront(8),
insertBack(9), eraseFront(), eraseBack(), insertFront(2),
insertBack(4), size(), empty(), front(), back()
30
Class Exercise 3: Solution
(Cont’d)
Operation Output 𝑫
insertFront(8) - (8,3,5,10,6)
insertFront(5) - (5)
insertBack(9) - (8,3,5,10,6,9)
insertBack(10) - (5,10)
eraseFront() - (3,5,10,6,9)
insertFront(3) - (3,5,10)
eraseBack() - (3,5,10,6)
insertBack(7) - (3,5,10,7)
insertFront(2) - (2,3,5,10,6)
insertFront(1) - (1,3,5,10,7)
insertBack(4) - (2,3,5,10,6,4)
eraseFront() - (3,5,10,7)
Size() 6 (2,3,5,10,6,4)
eraseBack() - (3,5,10)
empty() false (2,3,5,10,6,4)
insertBack(6) - (3,5,10,6)
front() 2 (2,3,5,10,6,4)
front() 3 (3,5,10,6)
back() 4 (2,3,5,10,6,4)
back() 6 (3,5,10,6)
31
The STL Deque
▪ As with the stack and queue, the Standard Template Library provides an
implementation of a deque.
▪ The underlying implementation is based on the STL vector class.
▪ First, include the definition file “deque”.
▪ Since it is a member of the std namespace, there is need to either preface
each usage “std::deque” or provide an appropriate “using” statement.
▪ As with STL stacks and queues, an STL deque dynamically resizes itself as
new elements are added.
32
The STL Deque
▪ The deque class is templated with the base type of the individual elements.
For example, the code fragment below declares a deque of strings.
#include <deque>
using std::deque; // make deque accessible
deque<string> myDeque; // a deque of strings
33
The STL Deque
▪ Also, the table shows a list of the principal operations:
Operation Description
push_front(𝑒) Insert 𝑒 at the beginning the deque.
push_back(𝑒) Insert 𝑒 at the end of the deque.
pop_front() Remove the first element of the deque.
pop_back() Remove the last element of the deque.
front() Return a reference to the deque’s first element.
back() Return a reference to the deque’s last element.
size() Return the number of elements in the deque.
empty() Return true if the deque is empty and false otherwise.
34
The STL Deque
▪ Similar to STL stacks and queues, the result of applying any of the
operations front, back, push_front, or push_back to an empty STL
queue is undefined.
▪ Thus, no exception is thrown, but the program may abort.
35
Case Study (Deque):
Managing a Customer Queue in a Bank
▪ You have been hired to design and implement a customer service queue system
for a bank. The system needs to handle both regular and VIP customers, allowing
for the following operations:
▪ VIP customers always want to be served immediately, so they are inserted at the
front of the queue.
▪ Regular customers are inserted at the back of the queue.
▪ Customers can leave the queue either from the front (after being served) or from the
back (if they leave the line voluntarily).
▪ You need to keep track of the first and last customer in the queue at any time.
▪ Additionally, you need to be able to check if the queue is empty and determine the
current size of the queue.
36
Case Study (Deque):
Managing a Customer Queue in a Bank
▪ Implementing the following operations on a deque to model the customer queue:
insertFront(𝒙) ▪ Add customer 𝑥 (VIP) to the front of the queue.
37
Class Exercise 4
▪ Consider the following sequence of 30 operations on a customer service queue for a
bank that handles both VIP (inserted in front) and regular customers (inserted at the
back).
Operations: insertFront("David"); insertBack("Mary"); insertFront("Moses");
insertBack("Ruth"); front(); back(); size(); eraseFront(); insertFront("Abraham");
insertBack("Sarah"); insertFront("Esther"); front(); back(); size(); insertBack("Solomon");
insertFront("Daniel"); eraseBack(); insertBack("Job"); eraseFront(); eraseBack();
insertFront("Joseph"); empty(); insertBack("Deborah"); insertFront("Ezekiel"); size();
front(); back(); eraseFront(); eraseBack(); insertBack("Naomi")
▪ After executing all operation:
a) What are the elements in the queue?
b) What is the element in the front of Queue?
c) What is the element at the back of Queue?
d) What is the size of Queue? 38
Class Exercise 4: Solution
▪ After all operations, the deque will have the following state (from front to
back):
a) Elements in the queue: (Joseph, Esther, Abraham, David, Mary, Ruth,
Sarah, Naomi)
b) Front of Queue: Joseph
c) Back of Queue: Naomi
d) Size of Queue: 8
▪ A priority queue is a data structure that stores elements in a way that each
has a "priority" associated with it.
▪ In a priority queue, elements are dequeued based on priority rather than the
order in which they were added,
▪ with higher-priority elements being served before lower-priority ones.
▪ Each element has an associated priority, and the queue serves elements according to
these priorities.
41
Priority Queue
▪ A priority queue is like a VIP line at an airport.
▪ Imagine there are passengers with different boarding priorities: first-class,
business-class, and economy.
▪ In a priority queue, people with higher priority (like first-class passengers) get to board
before others, even if they arrived later than some economy passengers.
▪ Similarly, in a priority queue data structure, elements with higher priority are removed
(or accessed) first, regardless of when they were added to the queue.
▪ In other words, while a regular queue serves on a first-come, first-served basis, a
priority queue serves based on priority level.
42
Priority-queue Analogy 43
The Priority Queue Abstract Data Type
▪ A priority queue is an abstract data type for storing a collection of
prioritized elements that supports arbitrary element insertion but supports
removal of elements in order of priority.
▪ That is, the element with first priority can be removed at any time.
▪ This ADT is fundamentally different from the position-based data structures
such as stacks, queues, deques, lists, and even trees.
▪ The priority queue ADT stores elements according to their priorities, and
has no external notion of “position.”
44
Keys
▪ Formally, a key is defined to be an object that is assigned to an element as a specific
attribute for that element and that can be used to identify, rank, or weigh that
element.
▪ The key is assigned to an element, typically by a user or application; hence, a key
might represent a property that an element did not originally possess.
▪ For example, in a database of customers, each entry might originally consist only of a name
and email address. However, to facilitate targeted marketing, a "loyalty tier" key (e.g.,
bronze, silver, gold) can be assigned to each customer.
▪ This key represents a property (loyalty level) that the customer data did not originally
possess, enabling more tailored interactions.
45
Keys
▪ The key an application assigns to an element is not necessarily unique. An
application may even change an element’s key if it needs to.
▪ For example, we can compare companies by earnings or by number of employees; hence,
either of these parameters can be used as a key for a company, depending on the
information we wish to extract.
▪ A key can sometimes be a more complex property that cannot be quantified with
a single number.
▪ For example, the priority of standby passengers is usually determined by taking into
account a host of different factors, including frequent-flyer status, the fare paid, and check-
in time.
46
Total Order Relations
▪ A total order is a rule for comparing keys that’s clear, logical, and always
consistent i.e., we know exactly where each item should be in the order.
▪ For example, imagine you have a list of tasks with different priorities e.g.,
▪ Task A with priority 2
▪ Task B with priority 5
▪ Task C with priority 1
▪ To keep this list organized, we need a comparison rule that lets us order these
tasks without any confusion.
▪ Hence, a priority queue needs a comparison rule that never contradicts itself.
47
Total Order Relations
▪ The comparison rule (usually denote by ≤) must define a total order relation in
order for it to be robust.
▪ The comparison rule is defined for every pair of keys and it must satisfy the
following properties:
▪ Reflexive property: 𝑘 ≤ 𝑘
▪ Antisymmetric property: if 𝑘1 ≤ 𝑘2 𝑎𝑛𝑑 𝑘2 ≤ 𝑘1 , 𝑡ℎ𝑒𝑛 𝑘1 = 𝑘2
▪ Transitive property: if 𝑘1 ≤ 𝑘2 𝑎𝑛𝑑 𝑘2 ≤ 𝑘3 , 𝑡ℎ𝑒𝑛 𝑘1 ≤ 𝑘3
▪ Any comparison rule, ≤, that satisfies these three properties never leads to a
comparison contradiction.
48
Fundamental Functions of a Priority Queue
▪ A priority queue is a container of elements, each associated with a key.
▪ The name “priority queue” comes from the fact that keys determine the “priority” used
to pick elements to be removed.
▪ The fundamental functions of a priority queue 𝑷 are as follows:
Functions Description
insert(𝑒) Insert the element 𝑒 (with an implicit associated key value) into 𝑃.
min() Return an element of 𝑃 with the smallest associated key value, that
is, an element whose key is less than or equal to that of every other
element in 𝑃.
removeMin() Remove from 𝑃 the element min().
49
Fundamental Functions of Priority Queue
▪ Note that more than one element can have the same key,
▪ which is why removeMin function is defined to remove not just any minimum element,
but the same element returned by min function.
▪ removeMin function is also referred to as extractMin.
▪ There are many applications where operations insert and removeMin play an
important role. We consider such an application in the example that follows (next
slide).
50
Example to illustrate insert and removeMin operations
▪ Suppose a certain flight is fully booked an hour prior to departure. Because of the
possibility of cancellations, the airline maintains a priority queue of standby passengers
hoping to get a seat.
▪ The priority of each passenger is determined by the fare paid, the frequent-flyer
status, and the time when the passenger is inserted into the priority queue.
▪ When a passenger requests to fly standby,
▪ the associated passenger object is inserted into the priority queue with an insert
operation.
▪ Shortly before the flight departure, if seats become available (for example, due to last-
minute cancellations),
▪ the airline repeatedly removes a standby passenger with first priority from the
priority queue, using a combination of min and removeMin operations, and lets this
person board.
51
The Priority Queue ADT
▪ As an ADT, a priority queue 𝑃 supports the following functions:
Function Description
insert(𝑒) Insert a new element 𝑒 into P.
min() Return a reference to an element of P with the smallest associated key
value (but do not remove it); an error condition occurs if the priority
queue is empty.
removeMin() Remove from P the element referenced by min(); an error
condition occurs if the priority queue is empty.
size() Return the number of elements in P.
empty() Return true if P is empty and false otherwise
▪ Note: 𝒔𝒊𝒛𝒆 and 𝒆𝒎𝒑𝒕𝒚 are generic collection operations
52
The Priority Queue ADT Operations
▪ The following table shows a series of
operations and their effects on an
initially empty priority queue 𝑃.
▪ Each element consists of an integer,
which we assume to be sorted
according to the natural ordering of
the integers.
▪ Note that each call to min returns a
reference to an entry in the queue,
not the actual value.
▪ Note: Although the “Priority Queue”
column shows the items in sorted
order, the priority queue need not
store elements in this order.
53
Class Exercise 5
#include <queue>
using namespace std; // make std accessible
priority_queue<int> p1; // a priority queue of integers
57
The STL priority_queue Class
▪ Let 𝒑 be declared to be an STL priority queue, and let 𝒆 denote a single object
whose type is the same as the base type of the priority queue.
▪ For example, 𝒑 is a priority queue of integers, and 𝒆 is an integer.
▪ The principal member functions of the STL priority queue are given below.
Function Description
push(𝑒) Insert 𝑒 in the priority queue.
pop() Remove the element at the top of the priority queue.
top() Return a constant reference to the largest element of the
priority queue.
size() Return the number of elements in the priority queue.
empty() Return true if the priority queue is empty and false otherwise.
▪ Note: The STL priority queue functions top and pop access the largest item
in the queue according to priority order, rather than the smallest. 58
Case Study (Priority Queue):
Hospital Emergency Room Management System
▪ A hospital emergency room (ER) treats patients with varying levels of
urgency.
▪ Patients arrive randomly, each with a different severity level of their
condition, which determines the priority of their treatment.
▪ Patients with life-threatening conditions must be treated before those with
minor injuries, regardless of arrival time.
▪ The ER wants an efficient way to manage and treat patients based on their
priority levels.
59
Case Study (Priority Queue):
Hospital Emergency Room Management System
▪ The hospital can use a priority queue data structure to manage patient
treatment in the ER.
▪ Defining Priority Levels: Each patient is assigned a priority based on the
severity of their condition:
▪ Critical (highest priority)
▪ Serious
▪ Moderate
▪ Minor (lowest priority)
60
Case Study (Priority Queue):
Hospital Emergency Room Management System
61
Case Study (Deque):
Hospital Emergency Room Management System
▪ Implementing the following operations on a priority queue to model the ER:
▪ When a new patient arrives at the ER, they are added to the priority queue
insert (Add a New
with a priority level based on their condition severity (e.g., Critical, Serious,
Patient)
Moderate, Minor).
min (Get the Next ▪ This operation retrieves the patient with the highest priority (i.e., the most
Patient to Be Treated) severe condition) without removing them from the queue.
removeMin (Treat the ▪ This operation removes and returns the patient with the highest priority from
Next Patient) the queue.
size (Check the
▪ This operation returns the total number of patients currently waiting in the
Number of Patients
queue.
Waiting)
empty (Check if There
▪ This operation checks if the priority queue is empty (i.e., no patients are
Are Any Patients
waiting for treatment).
Waiting)
62
▪ Patients arrive at the ER with varying conditions.
▪ Using a priority queue where lower numerical values represent higher
priority.That is,
1 = Critical, 2 = Serious, 3 = Moderate, 4 = Minor
▪ Let’s say four patients arrive sequentially with different severity levels:
▪ Patient A: Critical (Priority 1);
▪ Patient B: Moderate (Priority 3);
▪ Patient C: Serious (Priority 2);
▪ Patient D: Minor (Priority 4)
Insert Operation 64
➢ min():
▪ Returns [Patient A].
▪ Priority Queue: [Patient A (1), Patient C (2), Patient B (3), Patient D (4)]
➢ RemoveMin():
▪ Removes Patient A from the priority queue since it was return by min() operation.
▪ Priority Queue: Patient C (2), Patient B (3), Patient D (4)]
➢ Size():
▪ Returns 3 as the size of the priority queue
▪ Priority Queue: Patient C (2), Patient B (3), Patient D (4)]
➢ empty():
▪ Returns false because the priority queue is not empty
▪ Priority Queue:
Patient C (2), Patient B (3), Patient D (4)]
67
EXERCISES
Exercise 1
▪ You are tasked with developing a simple customer service application for a bank. The bank needs a way
to manage customers waiting for assistance. When a customer arrives at the bank, they join the end of
the queue. When a customer service representative is available, the customer at the front of the queue
is served first.Write a C++ program to achieve the following:
▪ Implement a queue to manage the customers.
▪ Each customer has a name and a unique ID.
▪ Provide the following functionalities:
▪ Add a new customer to the queue (enqueue).
▪ Serve the customer at the front of the queue (dequeue).
▪ Display the current customer at the front of the queue.
▪ Display the total number of customers waiting in the queue.
▪ Check if the queue is empty.
69
Exercise 2
▪ You are tasked with implementing a simple task scheduler using a double-
ended queue (deque) in C++. The scheduler will manage a list of tasks, each
represented by an integer, and support the following operations:
▪ Add a new task to the front of the deque.
▪ Add a new task at the Back of the deque.
▪ Adds a new task to the back of the deque.
▪ Removes and processes the task from the front of the deque.
▪ Removes and processes the task from the back of the deque.
▪ Displays all current tasks in the deque from front to back.
70
Exercise 3
▪ Identify and explain five (5) application areas where queue, deque,
and priority queue data structures are used. For each application area,
provide a relevant example or scenario to illustrate its use.
71