Data Structure - Queues
Data Structure - Queues
Hung-Ming Chen
NCTU EE
Fall 2023
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 1
Education, Inc. All rights reserved. 0-13-140909-3
Introduction to Queues
• A queue is a waiting line – seen in daily life
– A line of people waiting for a bank teller
– A line of cars at a toll both
– "This is the captain, we're 5th in line for takeoff"
• What other kinds of queues can you think of
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 2
Education, Inc. All rights reserved. 0-13-140909-3
The Queue as an ADT
• A queue is a sequence of data elements
• In the sequence
– Items can be removed only at the front
– Items can be added only at the other end, the back
– First in, first out (FIFO)
• or FCFS
• Basic operations
– Construct a queue
– Check if empty
– Enqueue (add element to back)
– Front (retrieve value of element from front)
– Dequeue (remove element from front)
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 3
Education, Inc. All rights reserved. 0-13-140909-3
Designing and Building a Queue
Class Array-Based
• Consider an array in which to store a queue
void dequeue();
Precondition: None.
/*-----------------------------------------------------------------------
Postcondition: An empty Queue object has been constructed; myFront Remove value at front of queue (if any).
and myBack are initialized to -1 and myArray is an array with
QUEUE_CAPACITY elements of type QueueElement. Precondition: Queue is nonempty.
----------------------------------------------------------------------*/ Postcondition: Value at front of queue has been removed, unless queue
is empty; in that case, an error message is displayed and
execution is terminated.
bool empty() const; ----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------
Check if queue is empty. private:
/***** Data Members *****/
int myFront, myBack;
Precondition: None.
QueueElement myArray[QUEUE_CAPACITY];
Postcondition: True is returned if the queue is empty and false is }; // end of class declaration
returned otherwise.
#endif
7
----------------------------------------------------------------------*/
Implementation //--- Definition of display()
void Queue::display(ostream & out) const
/*-- Queue.cpp----------------------------------------------------------- {
This file implements Queue member functions. for (int i = myFront; i != myBack; i = (i + 1)%QUEUE_CAPACITY)
-------------------------------------------------------------------------*/
out << myArray[i] << " ";
#include <iostream> cout << endl;
using namespace std; }
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 10
Education, Inc. All rights reserved. 0-13-140909-3
Linked Queues
• Constructor initializes
myFront, myBack
• Front
– return myFront->data
• Dequeue
– Delete first node (watch for empty queue)
• Enqueue
– Insert node at end of list
• View LQueue.h declaration, Fig 8.3A
• Note definition, LQueue.cpp, Fig 8.3B
• Driver program, Fig. 8.3C
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 11
Education, Inc. All rights reserved. 0-13-140909-3
#include <iostream> LQueue.h
#ifndef LQUEUE /***** Assignment *****/
#define LQUEUE const Queue & operator= (const Queue & rightHandSide);
/*-----------------------------------------------------------------------
typedef int QueueElement; Assignment Operator
Precondition: None.
Postcondition: The linked list in the queue has been deallocated.
-----------------------------------------------------------------------*/
12
LQueue.h (cont’d)
void display(ostream & out) const; private:
/*-----------------------------------------------------------------------
Display values stored in the queue.
/*** Node class ***/
class Node
Precondition: ostream out is open. {
Postcondition: Queue's contents, from front to back, have been
public:
output to out.
-----------------------------------------------------------------------*/ QueueElement data;
Node * next;
QueueElement front() const;
//--- Node constructor
/*-----------------------------------------------------------------------
Retrieve value at front of queue (if any). Node(QueueElement value, Node * link = 0)
/*-------------------------------------------------------------------
Precondition: Queue is nonempty. Precondition: value and link are received
Postcondition: Value at front of queue is returned, unless the
queue is empty; in that case, an error message is displayed Postcondition: A Node has been constructed with value in its
and a "garbage value" is returned. data part and its next part set to link (default 0).
-----------------------------------------------------------------------*/ ------------------------------------------------------------------*/
void dequeue(); { data = value; next = link; }
/*-----------------------------------------------------------------------
Remove value at front of queue (if any). };
Precondition: Queue is nonempty.
Postcondition: Value at front of queue has been removed, unless typedef Node * NodePointer;
queue is empty; in that case, an error message is displayed
and execution allowed to proceed.
/***** Data Members *****/
-----------------------------------------------------------------------*/
NodePointer myFront, // pointer to front of queue
myBack; // pointer to back of queue
13
Implementation
//--- Definition of Queue destructor
Queue::~Queue()
{
// Set pointer to run through the queue
/*--- LQueue.cpp ---------------------------------------------------------- Queue::NodePointer prev = myFront,
This file implements LQueue member functions. ptr;
-------------------------------------------------------------------------*/
while (prev != 0)
{
#include <new>
using namespace std; ptr = prev->next;
delete prev;
#include "LQueue.h" prev = ptr;
}
//--- Definition of Queue constructor }
Queue::Queue() //--- Definition of assignment operator
: myFront(0), myBack(0) const Queue & Queue::operator=(const Queue & rightHandSide)
{} {
if (this != &rightHandSide) // check that not q = q
//--- Definition of Queue copy constructor
{
Queue::Queue(const Queue & original)
this->~Queue(); // destroy current linked list
{
myFront = myBack = 0; if (rightHandSide.empty()) // empty queue
if (!original.empty()) myFront = myBack = 0;
{ else
// Copy first node { // copy rightHandSide's list
myFront = myBack = new Queue::Node(original.front()); // Copy first node
myFront = myBack = new Queue::Node(rightHandSide.front());
// Set pointer to run through original's linked list
Queue::NodePointer origPtr = original.myFront->next; // Set pointer to run through rightHandSide's linked list
while (origPtr != 0) Queue::NodePointer rhsPtr = rightHandSide.myFront->next;
{
while (rhsPtr != 0)
myBack->next = new Queue::Node(origPtr->data);
{
myBack = myBack->next;
origPtr = origPtr->next; myBack->next = new Queue::Node(rhsPtr->data);
} myBack = myBack->next;
} rhsPtr = rhsPtr->next;
} }
}
}
return *this; 14
}
Implementation //--- Definition of front()
//--- Definition of empty()
QueueElement Queue::front() const
bool Queue::empty() const
{
{
return (myFront == 0); if (!empty())
} return (myFront->data);
else
//--- Definition of enqueue() {
void Queue::enqueue(const QueueElement & value) cerr << "*** Queue is empty "
{ " -- returning garbage ***\n";
Queue::NodePointer newptr = new Queue::Node(value); QueueElement * temp = new(QueueElement);
if (empty()) QueueElement garbage = *temp; // "Garbage" value
myFront = myBack = newptr;
delete temp;
else
return garbage;
{
myBack->next = newptr; }
myBack = newptr; }
}
} //--- Definition of dequeue()
void Queue::dequeue()
//--- Definition of display() {
void Queue::display(ostream & out) const if (!empty())
{ {
Queue::NodePointer ptr;
Queue::NodePointer ptr = myFront;
for (ptr = myFront; ptr != 0; ptr = ptr->next)
myFront = myFront->next;
out << ptr->data << " ";
out << endl; delete ptr;
if (myFront == 0) // queue is now empty
} myBack = 0;
}
else
cerr << "*** Queue is empty -- can't remove a value ***\n";
}
15
Driver
#include <iostream>
using namespace std;
cout << "Queue q2 empty? " << q2.empty() << endl;
#include "LQueue.h"
cout << "Front value in q2: " << q2.front() << endl;
void print(Queue q)
{ q.display(cout); } while (!q2.empty())
{
int main() cout << "Remove front -- Queue contents: ";
{ q2.dequeue();
Queue q1; q2.display(cout);
cout << "Queue created. Empty? " << boolalpha }
<< q1.empty() << endl; cout << "Queue q2 empty? " << q2.empty() << endl;
cout << "Front value in q2?" << endl << q2.front() << endl;
cout << "How many elements to add to the queue? "; cout << "Trying to remove front of q2: " << endl;
int numItems; q2.dequeue();
cin >> numItems; }
for (int i = 1; i <= numItems; i++)
q1.enqueue(100*i);
Queue q2;
q2 = q1;
cout << "Contents of queue q2 after q2 = q1 (via print):\n";
print(q2); cout << endl;
16
Execution Trace Sample
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 17
Education, Inc. All rights reserved. 0-13-140909-3
Execution Trace Sample
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 18
Education, Inc. All rights reserved. 0-13-140909-3
Circular Linked List
• Possible to treat the linked list as circular
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 21
Education, Inc. All rights reserved. 0-13-140909-3
Application of Queues:
Buffers and Scheduling
• Consider a keyboard buffer (interactive
input)
– Acts as a queue
– But elements may be
removed from the back of
the queue with
backspace key
• A printer spool (simultaneous peripheral
operation on-line) is a queue of print jobs
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 22
Education, Inc. All rights reserved. 0-13-140909-3
Application of Queues:
Buffers and Scheduling
• Queues used to
schedule tasks
within an operating
system
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 24
Education, Inc. All rights reserved. 0-13-140909-3
Application 2: Information
Center/Customer Service Simulation
• Most waiting lines (queues) are dynamic
– Their lengths grow and shrink over time
• Simulation models this dynamic process
– Enables study of the behavior of the process
– Modeled with one or more equations
• Queue behavior involves randomness
– We will use pseudorandom number generator
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 25
Education, Inc. All rights reserved. 0-13-140909-3
Problem Analysis and Specification
• Consider an information center
– Calls arrive at random intervals
– Placed in queue of incoming calls
– When agent becomes available, services call at
front of queue
• We will simulate receipt of "calls" for some
number of "minutes"
– we keep track of calls in the queue
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 26
Education, Inc. All rights reserved. 0-13-140909-3
Problem Analysis and Specification
• Input to the simulation program
– Time limit
– Arrival rate of calls
– Distribution of service times
• myServicePercent[0] = percent of calls serviced in 1
min or less
• Desired output
– Number of calls processed
– Average waiting time per call
• Note declaration of Simulation class, Fig. 8-4
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 27
Education, Inc. All rights reserved. 0-13-140909-3
#include <iostream>
Simulation Class
// istream, ostream, >>, <<
#include <ctime> // time() /***** Output *****/
void display(ostream & out);
#ifndef SIMULATION /*----------------------------------------------------------------------
#define SIMULATION Display results of the simulation.
Precondition: ostream out is open.
#include "Timer.h" Postcondition: Total number of calls and the average waiting time
#include "Call.h" for calls have been output to out.
#include "LQueue.h" // Queue with elements of type Call -----------------------------------------------------------------------*/
//-- Outputs
int myCallsReceived;
double myTotalWaitingTime;
#endif 29
Problem Analysis and Specification
• Constructor
– Initialize input data members
– myTimer, myIncomingCalls initialized by their
constructors
• The run() method
– Starts and manages simulation
• The checkForNewCall() method
– Random number generated, compared to myArrivalRate
– If new call has arrived, create new Call object, place in
queue
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 30
Education, Inc. All rights reserved. 0-13-140909-3
Problem Analysis and Specification
• The service() method
– Checks time remaining for current call
– When done, retrieves and starts up next call from front of
queue
• The display() method
– Report generated at end of simulation
• View definition of function members
Fig. 8-5A
• Note driver program for simulation, Fig. 8-5B
• Reference: the Timer class and Call class used in
the Simulation class
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 31
Education, Inc. All rights reserved. 0-13-140909-3
Implementation
/*-- Simulation.cpp --------------------------------------------------------
Definitions of function members of class Simulation.
-------------------------------------------------------------------------*/
//--- Definition of run()
#include <iostream> // istream, ostream, >>, <<
void Simulation::run()
#include <cstdlib> // rand(), srand()
{
#include <ctime> // time()
using namespace std;
// Begin the simulation
int busyTimeRemaining = 0;
#include "Simulation.h" while (myTimer.timeRemaining() > 0)
{
//--- Definition of constructor service(busyTimeRemaining);
Simulation::Simulation() checkForNewCall();
{ myTimer.tick();
//-- Initialize output statistics }
myCallsReceived = 0; cout << "\nNot accepting more calls -- service those waiting\n";
myTotalWaitingTime = 0;
//-- Get simulation parameters
// Service any remaining calls in incomingCalls queue
cout << "Enter arrival rate (calls per hour): ";
while (!myIncomingCalls.empty())
int callsPerHour;
{
cin >> callsPerHour;
myArrivalRate = callsPerHour / 60.0; // convert to calls per minute
service(busyTimeRemaining);
myTimer.tick();
cout << "Enter percent of calls serviced in\n"; }
int percent,
sum = 0; // Output the results
for (int i = 0; i < NUM_CATEGORIES - 1; i++) display(cout);
{ }
cout << " <= " << i + 1 << " min. "; cin >> percent;
sum += percent; //--- Definition of display()
myServicePercent[i] = sum; void Simulation::display(ostream & out)
}
{
myServicePercent[NUM_CATEGORIES - 1] = 100;
out << "\nNumber of calls processed: " << myCallsReceived
cout << "Enter # of minutes to run simulation: ";
<< "\nAve. waiting time per call: "
cin >> myLengthOfSimulation;
<< myTotalWaitingTime / myCallsReceived
<< " minutes" << endl;
// Set the countdown timer }
myTimer.set(myLengthOfSimulation);
33
Call.h
/*-- Call.h ---------------------------------------------------
int getArrivalTime() const;
/*----------------------------------------------------------
This header file defines a class Call that models phone calls. Accessor function for arrival time.
Basic operations: Precondition: None
constructors: construct a Call object Postcondition: Value of myTimeOfArrival was returned.
getArrivalTime(): accessor to get time call arrived -----------------------------------------------------------*/
getServiceTime(): get time needed to service the call
display(): display information about the call int getServiceTime() const;
<<: output operator for a Call object /*----------------------------------------------------------
--------------------------------------------------------------*/
Accessor function for service time.
#include <iostream>
Precondition: None
#include "Timer.h"
Postcondition: Value of myServiceTime was returned.
-----------------------------------------------------------*/
#ifndef CALL
#define CALL
void display(ostream & out) const;
class Call
/*----------------------------------------------------------
{ Display call
public: Precondition: ostream out is a reference parameter
/***** Function Members *****/ Postcondition: Call has been output to out.
/***** Constructor *****/ -----------------------------------------------------------*/
Call();
/*---------------------------------------------------------- private:
Construct a Call object (default). /***** Data Members *****/
Precondition: None int myTimeOfArrival;
Postcondition: All data members are initialized to 0. int myServiceTime;
-----------------------------------------------------------*/ }; // end of Timer class declaration
Call(const Timer & t, int serviceTime);
/*----------------------------------------------------------
Construct a Call object (explicit-value). //--- Prototype for output operator
Precondition: Countdown timer t is received ostream & operator<<(ostream & out, const Call & aCall);
Postcondition: myTimeOfArrival has been set to time left
on Timer t and myServiceTime to serviceTime.
#endif 34
-----------------------------------------------------------*/
Call Implementation
/*-- Call.cpp -------------------------------------------------- //--- Definition of getArrivalTime()
Contains definitions of the basic Call operations. int Call::getArrivalTime() const
--------------------------------------------------------------*/ {
return myTimeOfArrival;
#include <iostream> }
#include <cassert>
using namespace std; //--- Definition of getServiceTime()
int Call::getServiceTime() const
#include "Call.h" {
return myServiceTime;
}
//--- Definition of Default Constructor
Call::Call() //--- Definition of display()
{ void Call::display(ostream & out) const
myTimeOfArrival = myServiceTime = 0; {
} out << "Arrival Time: " << myTimeOfArrival << endl
<< "Service Time: " << myServiceTime << endl;
//--- Definition of Explicit-Value Constructor }
Call::Call(const Timer & t, int serviceTime)
{ //-- Definition of output operator
// record call's time of arrival ostream & operator<<(ostream & out, const Call & aCall)
myTimeOfArrival = t.timeRemaining(); {
aCall.display(out);
// set its service time return out;
myServiceTime = serviceTime; }
}
35
Driver
/*-------------------------------------------------------------
Driver program for simulation of information/reservation
center that services telephone calls
--------------------------------------------------------------*/
#include "Simulation.h"
int main()
{
Simulation sim;
sim.run();
return 0;
}
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 36
Education, Inc. All rights reserved. 0-13-140909-3
Execution Trace
Enter arrival rate (calls per hour): 15
Enter percent of calls serviced in
<= 1 min. 50
<= 2 min. 25
<= 3 min. 15
<= 4 min. 7
Enter # of minutes to run simulation: 500
Not accepting more calls – service those waiting
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 37
Education, Inc. All rights reserved. 0-13-140909-3
Application 3: Image-Component Labeling
1. Stack ok?
2. Complexity?
41