Ch06 Queues

  • Uploaded by: metin tekin
  • 0
  • 0
  • December 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Ch06 Queues as PDF for free.

More details

  • Words: 3,181
  • Pages: 65
Queues

Chapter Outline • Representing a waiting line, i.e., queue • The methods of the queue ADT: push, front, pop, empty, and size • Implement the queue ADT: • As an adapter of a the std::list • Singly-linked list • Circular array (a.k.a., circular buffer) • The deque • Applications of queues: • Simulating physical systems with waiting lines ... • Using Queues and random number generators Chapter 6: Queues

2

The Queue Abstract Data Type • Visualization: queue = line of customers waiting for some service • In Britain, it is the common word for this • Next person served is one who has waited longest: • First-in, First-out = FIFO • New elements are placed at the end of the line • Next served is one at the front of the line

Chapter 6: Queues

3

A Print Queue • Operating systems use queues to • Track tasks waiting for a scarce resource • Ensure tasks carried out in order generated • Print queue: • Printing slower than selecting pages to print • So use a queue, for fairness • A stack would be inappropriate (more in a moment) • (Consider multiple queues, priorities, etc., later) Chapter 6: Queues

4

A Print Queue (continued)

Chapter 6: Queues

5

Unsuitability of a Print Stack • Stacks are last-in, first-out (LIFO) • Most recently selected document would print next • Unless queue is empty, your job may never execute • ... if others keep issuing print jobs

Chapter 6: Queues

6

Specification of the Queue ADT

Function

Behavior

Item_Type& front(); const Item_Type& front() const void pop() void push(const Item_Type&) size_t size() const

Returns true if the queue is empty; otherwise returns false. Returns the object that is at the front of the queue without removing it. Removes the object at the front of the queue. Pushes an item onto the rear of the queue. Returns the number of items in the queue.

bool empty() const

Chapter 6: Queues

7

Maintaining a Queue of Customers Problem: Write a menu-driven program that: • Maintains a list of customers waiting for service • Can add a new customer at the end • Can display name of next customer to serve • Can display the length of the line

Chapter 6: Queues

8

Maintaining a Queue of Customers (2) Analysis: Because service is in FIFO order, a queue is the appropriate data structure • Top level algorithm: while user not finished, • Display menu and obtain choice, then • Perform the selected operation • The operations are all basic queue operations ...

Chapter 6: Queues

9

Maintain_Queue.cpp int main() { queue<string> customers; string name; int choice_num = 0; string choices[] = {"push", "front", "pop", "size", "quit"}; const int NUM_CHOICES = 5; // Perform all operations selected by user. while (choice_num < NUM_CHOICES - 1) { // Select the next operation. cout << "Select an operation on customer queue\n"; for (int i = 0; i < NUM_CHOICES; i++) { cout << i << ": " << choices[i] << endl; } cin >> choice_num; switch (choice_num) { . . . } // End while. return 0; } Chapter 6: Queues

10

Insert a new customer case 0: cout << "Enter new customer name\n"; cin >> name; customers.push(name); break;

Chapter 6: Queues

11

Display the Next Customer case 1: cout << "Customer " << customers.front() << " is next in line\n"; break;

Chapter 6: Queues

12

Remove the Next Customer case 2: cout << "Customer " << customers.front() << " removed from line\n"; customers.pop(); break;

Chapter 6: Queues

13

Display the Length of the Line case 3: cout << "Size of line is " << customers.size() << endl; break;

Chapter 6: Queues

14

Exit the Program case 4: cout << << << break; default: cout << break;

"Leaving customer queue.\n" "Number of customers in queue is " << customers.size() endl; "Invalid selection\n";

Chapter 6: Queues

15

Implementing Queue: adapter of std::list • This is a simple adapter class, with following mappings: • Queue push maps to push_back • Queue front maps front • Queue pop maps to pop_front • ... • This is the approach taken by the C++ standard library. • Any sequential container that supports push_back, front, and pop_front can be used. • The list • The deque Chapter 6: Queues

16

Implementing Queue: Singly-Linked List This requires front and rear Node pointers: template class queue { . . . private: // Insert implementation-specific data fields // Insert definition of Node here #include "Node.h" // Data fields Node* front_of_queue; Node* back_of_queue; size_t num_items; }; Chapter 6: Queues

17

Using a Single-Linked List to Implement a Queue (continued)

Chapter 6: Queues

18

Implementing Queue: Singly-Linked List (2) • Insert at tail, using back_of_queue for speed • Remove using front_of_queue • Adjust size when adding/removing • No need to iterate through to determine size

Chapter 6: Queues

19

Implementing Queue: Singly-Linked List (3) template void queue::push(const Item_Type& item) { if (front_of_queue == NULL) { back_of_queue = new Node(item, NULL); front_of_queue = back_of_queue; back_of_queue = new Node(item, NULL); front_of_queue = back_of_queue; } else { back_of_queue->next = new Node(item, NULL); back_of_queue = back_of_queue->next; } num_items++; } Chapter 6: Queues

20

Implementing Queue: Singly-Linked List (4) template Item_Type& queue::front() { return front_of_queue->data; }

Chapter 6: Queues

21

Implementing Queue: Singly-Linked List (4) template void queue::pop() { Node* old_front = front_of_queue; front_of_queue = front_of_queue->next; if (front_of_queue == NULL) { back_of_queue = NULL; } delete old_front; num_items--; }

Chapter 6: Queues

22

Analysis of the Space/Time Issues • Time efficiency of singly- or doubly-linked list good: O(1) for all Queue operations • Space cost: ~3 extra words per item • vector uses 1 word per item when fully packed • 2 words per item when just grown • On average ~1.5 words per item, for larger lists

Chapter 6: Queues

23

Analysis of the Space/Time Issues (2) • vector Implementation • Insertion at end of vector is O(1), on average • Removal from the front is linear time: O(n) • Removal from rear of vector is O(1) • Insertion at the front is linear time: O(n)

Chapter 6: Queues

24

Implementing queue With a Circular Array Basic idea: Maintain two integer indices into an array • front: index of first element in the queue • rear: index of the last element in the queue • Elements thus fall at front through rear Key innovation: • If you hit the end of the array wrap around to slot 0 • This prevents our needing to shift elements around • Still have to deal with overflow of space Chapter 6: Queues

25

Implementing Queue With Circular Array (2)

Chapter 6: Queues

26

Implementing Queue With Circular Array (3)

Chapter 6: Queues

27

Implementing Queue With Circular Array (4)

Chapter 6: Queues

28

Implementing queue with a circular array template class queue { public: . . . private: // Insert implementation-specific data fields void reallocate(); // Data fields static const size_t DEFAULT_CAPACITY = 10; size_t capacity; size_t num_items; size_t front_index; size_t rear_index; Item_Type* the_data; };

Chapter 6: Queues

29

Implementing queue with a circular array(2) template queue::queue() : capacity(DEFAULT_CAPACITY), num_items(0), front_index(0), rear_index(DEFAULT_CAPACITY - 1), the_data(new Item_Type[DEFAULT_CAPACITY]) {}

Chapter 6: Queues

30

Implementing queue with a circular array(3) template void queue::push(const Item_Type& item) { if (num_items == capacity) { reallocate(); } num_items++; rear_index = (rear_index + 1) % capacity; the_data[rear_index] = item; }

// Cost: O(1) (even on average when grows)

Chapter 6: Queues

31

Implementing queue with a circular array(4) template Item_Type& queue::front() { return the_data[front_index]; } template void queue::pop() { front_index = (front_index + 1) % capacity; num_items--; }

Chapter 6: Queues

32

Reallocating a Circular Array

Chapter 6: Queues

33

Implementing queue::reallocate void queue::reallocate() { size_t new_capacity = 2 * capacity; Item_Type* new_data = new Item_Type[new_capacity]; /*<snippet id="4" omit="false">*/ size_t j = front_index; for (size_t i = 0; i < num_items; i++) { new_data[i] = the_data[j]; j = (j + 1) % capacity; } /**/ front_index = 0; rear_index = num_items - 1; capacity = new_capacity; std::swap(the_data, new_data); delete[] new_data; } Chapter 6: Queues

34

Comparing the Three Implementations • All three are comparable in time: O(1) operations • Linked-lists require more storage • Singly-linked list: ~3 extra words / element • Doubly-linked list: ~4 extra words / element • Circular array: 0-1 extra word / element • On average, ~0.5 extra word / element

Chapter 6: Queues

35

The deque • The deque is an abstract data type that combines the features of a stack and a queue. • The name deque is an abbreviation for doubleended queue. • The C++ standard defines the deque as a fullfledged sequential container that supports random access.

Chapter 6: Queues

36

The deque class Member Function

const Item_Type& operator[](size_t index)const; Item_Type& operator[](size_t index) const Item_Type& at(size_t index) const; Item_Type& at(size_t index) iterator insert(iterator pos, const Item_Type& item) iterator erase(iterator pos) void remove(const Item_Type& item)

Behavior Returns a reference to the element at position index. Returns a reference to the element at position index. If index is not valid, the out_of_range exception is thrown. Inserts a copy of item into the deque at position pos. Returns an iterator that references the newly inserted item. Removes the item from the deque at position pos. Returns an iterator that references the item following the one erased. Removes all occurrences of item from the deque.

Chapter 6: Queues

37

The deque class (2) Member Function

void push_front(const Item_Type& item) void push_back(const Item_Type& item) void pop_front() void pop_back() Item_Type& front(); const Item_Type& front() const Item_Type& back(); const Item_Type& back() const iterator begin() const_iterator begin() const

Behavior

Inserts a copy of item as the first element of the deque Inserts a copy of item as the last element of the deque. Removes the first item from the deque. Removes the last item from the deque. Returns a reference to the first item in the deque. Returns a reference to the last item in the deque. Returns an iterator that references the first item of the deque. Returns a const_iterator that references the first item of the deque.

Chapter 6: Queues

38

The deque class (3) Member Function iterator end()

Behavior

Returns an iterator that references one past the last item of the deque. const_iterator end() const Returns a const_iterator that references one past the last item of the deque. void swap(deque
Chapter 6: Queues

39

Implementing the Deque Using a Circular Array • We can add the additional functions to the circular array based queue. • queue::push is the same as deque::push_back • queue::pop is the same as deque::pop_front. • Implementing deque::push_front and deque::pop_back are left as exercises. • Operator[] is implemented as follows: Item_Type& operator[](size_t index){ return the_data[(index + front_index) % capacity]; }

Chapter 6: Queues

40

The Standard Library Implementation • The standard library uses a randomly accessible circular array. • Each item in the circular array points to a fixed size, dynamically allocated array that contains the data. • The advantage of this implementation is that when reallocation is required, only the pointers need to be copied into the new circular array. Chapter 6: Queues

41

The Standard Library Implementation (2)

Chapter 6: Queues

42

The index operator template Item_Type& deque::operator[](size_t i) { if (i >= num_items) throw std::out_of_range ("Invalid index to deque::operator[]"); int block_index = (offset + i) / BLOCK_SIZE; int data_index = (offset + i) % BLOCK_SIZE; return the_data[block_index][data_index]; }

Chapter 6: Queues

43

The push_back functions template void deque::push_back(const Item_Type& item) { int capacity = the_data.size() * BLOCK_SIZE; if ((num_items + offset) == capacity) { the_data.push_back(new Item_Type[BLOCK_SIZE]); } num_items++; (*this)[num_items - 1] = item; }

Chapter 6: Queues

44

The pop_front function template void deque::pop_front() { offset++; if (offset == BLOCK_SIZE) { delete[] the_data.front(); the_data.pop_front(); offset = 0; } num_items--; }

Chapter 6: Queues

45

Simulating Waiting Lines Using Queues • Simulation is used to study the performance: • Of a physical (“real”) system • By using a physical, mathematical, or computer model of the system • Simulation allows designers to estimate performance • Before building a system • Simulation can lead to design improvements • Giving better expected performance of the system Chapter 6: Queues

46

Simulating Waiting Lines Using Queues (2) • Simulation is particular useful when: • Building/changing the system is expensive • Changing the system later may be dangerous • Often use computer models to simulate “real” systems • Airline check-in counter, for example • Special branch of mathematics for these problems: Queuing Theory

Chapter 6: Queues

47

Simulate Strategies for Airline Check-In

Chapter 6: Queues

48

Simulate Airline Check-In • • 3. 4. 5. 6. 7.

We will maintain a simulated clock • Counts in integer “ticks”, from 0 At each tick, one or more events can happen: Frequent flyer (FF) passenger arrives in line Regular (R) passenger arrives in line Agent finishes, then serves next FF passenger Agent finishes, then serves next R passenger Agent is idle (both lines empty) Chapter 6: Queues

49

Simulate Airline Check-In (2) •

Simulation uses some parameters: • Max # FF served between regular passengers • Arrival rate of FF passengers • Arrival rate of R passengers • Service time • Desired output: • Statistics on waiting times, agent idle time, etc. • Optionally, a detailed trace Chapter 6: Queues

50

Simulate Airline Check-In (3) •

Design approach: • Agent data type models airline agent • Passenger data type models passengers • 2 queue<Passenger>, 1 for FF, 1 for R • Overall Airline_Checkin_Sim class

Chapter 6: Queues

51

Simulate Airline Check-In (4)

Chapter 6: Queues

52

Airline_Checkin_Sim Design Data Field

Attribute

Passenger_Queue frequent_flyer_queue Passenger_Queue regular_passenger_queue int frequent_flyer_max

The queue of frequent flyers. The queue of regular passengers

int max_processing_time int total_time bool show_all int clock int frequent_flyers_since_RP

Function void void void void

run_simulation() enter_data() start_serve() show_stats()

The maximum number of frequent flyers to serve between regular passengers. The maximum time to serve a passenger. The total time to run the simulation. A flag indicating whether to trace the simulation. The current clock time The number of frequent flyers served since the last regular passenger.

Behavior

Controls the simulation. Reads in the data for the simulation Initiates service for a passenger. Displays the summary statistics. Chapter 6: Queues

53

Passenger_Queue Design Data Field

Attribute

int total_wait

The queue of passengers The number from this queue that were served. The total time spent waiting by passengers that were in this queue. The name of this queue. The arrival rate for this queue.

queue<Passenger> the_queue int num_served

string queue_name double arrival_rate

Function

Behavior

Passenger_Queue(string Constructs a new queue with the specified queue_name) name. void check_new_arrival(int clock, Checks whether there was a new arrival for bool show_all) this queue and, if so, inserts a passenger int update(int clock, bool show_all) int get_total_wait() const int get_num_served() const

into the queue. Updates the total waiting time and number of passengers served when a passenger from this queue is served. Returns the total waiting time. Returns the number of passengers served. Chapter 6: Queues

54

Passenger Design Data Field

int passenger_id int processing_time int arrival_time static int max_processing_time static int id_num

Function

Passenger(int arrival_time)

int get_arrival_time() const int get_processsing_time() const static void set_max_processing_time(int max_process_time)

Attribute The ID number for this passenger The time needed to process this passenger The time this passenger arrives The maximum time to process a passenger The sequence number for passengers

Behavior

Constructs a new passenger, assigns a unique ID and the specified arrival time. Computes a random processing time in the range 1 to max_processing_time. Returns arrival_time Returns processing_time Sets the max_processing_time.

Chapter 6: Queues

55

The main function int main() { Airline_Checkin_Sim simulation; simulation.enter_data(); simulation.run_simulation(); simulation.show_stats(); }

Chapter 6: Queues

56

The enter_data function Internal variable

frequent_flyer_queue.arrival_rate

Attribute

Expected number of frequent flyer arrivals per hour. regular_passenger_queue.arrival_rate Expected number of regular passenger arrivals per hour. max_processing_time Maximum service time in minutes. total_time Total simulation time. show_all Flag, if true display minuteby-minute trace of simulation. Chapter 6: Queues

Conversion Divide input by 60 to obtain arrivals per minute. Divide input by 60 to obtain arrivals per minute. None None. If input begins with 'y' or 'Y' set to true.

57

The run_simulation function void Airline_Checkin_Sim::run_simulation() { for (clock = 0; clock < total_time; clock++) { frequent_flyer_queue.check_new_arrival(clock, show_all); regular_passenger_queue.check_new_arrival(clock, show_all); if (clock >= time_done) { start_serve(); } } }

Chapter 6: Queues

58

The start_serve function void Airline_Checkin_Sim::start_serve() { if (!frequent_flyer_queue.empty() && ( (frequent_flyers_since_RP <= frequent_flyer_max) || regular_passenger_queue.empty())) { // Serve the next frequent flyer. frequent_flyers_since_RP++; time_done = frequent_flyer_queue.update(clock, show_all); } else if (!regular_passenger_queue.empty()) { // Serve the next regular passenger. frequent_flyers_since_RP = 0; time_done = regular_passenger_queue.update(clock, show_all); } else if (show_all) { cout << "Time is " << clock << ": Server is idle\n"; } } Chapter 6: Queues

59

Passenger_Queue::check_arrival void Passenger_Queue::check_new_arrival(int clock, bool show_all) { if (my_random.next_double() < arrival_rate) { the_queue.push(Passenger(clock)); if (show_all) { cout << "Time is " << clock << ": " << queue_name << " arrival, new queue size is " << the_queue.size() << endl; } } }

Chapter 6: Queues

60

Passenger_Queue::update int Passenger_Queue::update(int clock, bool show_all) { Passenger next_passenger = the_queue.front(); the_queue.pop(); int time_stamp = next_passenger.get_arrival_time(); int wait = clock - time_stamp; total_wait += wait; num_served++; if (show_all) { cout << "Time is " << clock << ": Serving " << queue_name << " with time stamp " << time_stamp << endl; } return clock + next_passenger.get_processing_time(); }

Chapter 6: Queues

61

Passenger Implementation Passenger::Passenger(int arrive_time) { arrival_time = arrive_time; processing_time = 1 + my_random.next_int(max_processing_time); passenger_id = id_num++; }

Chapter 6: Queues

62

Concerning “Random” Numbers • Not really random, but pseudo-random • Generated by a definite algorithm • Next produced from the last • Thus, sequence determined by starting value • Starting value is called the seed • Seed usually set from date/time, but can set directly to get same sequence on each occasion • Good for testing!

Chapter 6: Queues

63

Concerning “Random” Numbers (2) • The C++ standard library contains the functions rand and srand. • These are declared in and are the same as used by C. • The function rand generates an integer between 0 and RAND_MAX. • The function srand sets the starting value (known as the seed). • If the same seed is used, the same sequence of random numbers is generated. Chapter 6: Queues

64

The Random class

/** Class to encapsulate the standard random number generator. */ class Random { public: Random() { std::srand(std::time(0)); } Random(int seed) { std::srand(seed); } int next_int(int n) { return int(next_double() * n); } double next_double() { return double(std::rand()) / RAND_MAX; } };

Chapter 6: Queues

65

Related Documents

Ch06 Queues
December 2019 6
Queues
November 2019 3
Ch06
October 2019 15
Ch06
June 2020 14
Priority Queues
November 2019 6
Ch06
October 2019 11

More Documents from ""