topics: implementing queues & priority queues simulation...

Post on 03-Sep-2020

2 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

CS302Topics: Implementing Queues & Priority Queues

Simulation with Priority Queues

“Gone out –Here is a computer simulationof your dinner”

The banking simulation,Part I

Thursday,Sept. 28, 2006

AnnouncementsLab 3 (Graphical Stock Charts); due this Monday, Oct. 2

Don’t procrastinate!!

I like work: it fascinates me. I like work: it fascinates me.

I can sit and look at it for hours. I can sit and look at it for hours.

---- J.K. Jerome (Three Men in a Boat, 1889)J.K. Jerome (Three Men in a Boat, 1889)

Lab 4 (Algorithm Analysis)

Will be made available this evening

Due: Wednesday, Oct. 11

Recall: What are properties of Priority Queue / Heap?

What are the properties of a heap?Structure property:

Complete binary tree. In other words, tree is completely filled, with possible exception of last level, which is filled from left to right

Heap-Order property (for a min heap):For every internal node v other than the root,

key(v) ≥ key(parent(v))

Heap

Recall: What are Priority Queue / Heap Runtimes?

Time complexities:insert:

O(log n), worst caseO(1), on average

Can be shown that, on average, don’t have to percolate new element all the way upOn average, percolation terminates earlyOn average, 2.607 comparisons are required to perform an insert

deleteMin:O(log n)

buildHeap:O(n)

Heap

Array-Based Heap ImplementationWe can represent heap with nkeys by means of a vector of length n +1For the node at rank i

The left child is at rank 2iThe right child is at rank 2i+1

Links between nodes are not explicitly storedThe cell at rank 0 is not usedOperation insert corresponds to inserting at rank n+1Operation deleteMincorresponds to removing at rank n

2

5

9 7

6

1

2 3

4 5

2 5 6 9 7

1 2 3 4 50 6

Another example that maps “tree” structure to heap array

2

5

9 7 2 6

12 11

6

1

2 3

4 5 6 7

8 9

2 5 6 9 7 2 6 12 111 2 3 4 5 6 7 8 9 10 0

Animation of Priority Queue

http://www.cs.auckland.ac.nz/software/AlgAnim/heaps.html

STL C++ Implementation of Queues

Queue -- usual FIFO data structure:

back() front()

Queuepush() pop()

push() // inserts element into end of queueback() // returns last element in queuepop() // removes next element from front of queuefront() // returns next element (at front) in queuesize() // returns the current number of elementsempty() // returns whether queue is empty

To use, include following header:#include <queue>

Constructing Queues

queue <type> q; // default, creates an empty queuequeue <type> s(q); // creates queue initialized by elements of q

Example of using Queues#include <iostream>#include <queue>#include <string>using namespace std;

int main(){ queue<string> q;

q.push(“These “);q.push(“are “);q.push(“more than “);

cout << q.front();q.pop();cout << q.front();q.pop();

q.push(“four “);q.push(“words!”);q.pop();

cout << q.front();q.pop();cout << q.front() << endl;q.pop();cout << “number of elements in the queue: “ << q.size() << endl;

}

Output?These are four words!number of elements in the queue: 0

STL Implementation of Priority Queues

Priority queue -- similar to queue, but elements are in order according to priority:

You provide sorting criterion as template parameter

Default is “<“ (results in MAX Priority Queue)

top()

Priority Queuepush() pop()

push() // inserts element into priority queuetop() // returns next element in priority queuepop() // removes element from priority queuesize() // returns the current number of elementsempty() // returns whether queue is empty

Constructing Priority Queuespriority_queue <type> q; // default, creates an empty p. queue

// with comparison operator <

priority_queue <type, storage> q; // creates p. queue // stored in “storage”, with // comparison operator <

example:priority_queue <float, vector<float> > q;

priority_queue <type, storage, compare> q; // creates p. queue // stored in “storage”, with // comparison operator “compare”

example:priority_queue <float, vector<float>, greater<float> > q;

Example #1 of using Priority Queues

#include <iostream>#include <queue> //NOTICE YOU STILL USE <queue> !!using namespace std;

int main(){ priority_queue<float> q;

q.push(66.6);q.push(22.2);q.push(44.4);

cout << q.top() << ‘ ‘;q.pop();cout << q.top() << endl;q.pop();

q.push(11.1);q.push(55.5);q.push(33.3);q.pop();

while (!q.empty()) {cout << q.top() << ‘ ‘;q.pop();

}cout << endl;

}

Output?66.6 44.4 33.3 22.2 11.1

Example #2 of using Priority Queues#include <iostream> #include <queue> using namespace std;

class data { public: float x;

};

bool operator<(data x1, data x2) { return (x1.x < x2.x); // putting in reverse order is easy,

// just change the < to a > }

int main() { priority_queue<data> q; data a, b, c, d, e;

a.x = 14; b.x = 2; c.x = 34; d.x = 304; e.x = 10;

q.push(a); q.push(b); q.push(c); q.push(d); q.push(e);

while(!q.empty()) { cout << q.top().x << ' '; q.pop();

} cout << endl;

}

Output?304 34 14 10 2

Summary Example #1#include <iostream> #include <queue> using namespace std;

void functionA() { queue <int> q;

q.push(2); q.push(5); q.push(3); q.push(1);

cout<<"q contains " << q.size() << " elements.\n";

while (!q.empty()) { cout << q.front() << endl; q.pop();

} }

int main() { functionA();

}

Output?q contains 4 elements.2 5 3 1

Summary Example #2#include <iostream> #include <queue> using namespace std;

void functionB() { priority_queue <int> pq;

pq.push(2); pq.push(5); pq.push(3); pq.push(1);

cout << "pq contains " << pq.size() << " elements.\n";

while (!pq.empty()) { cout << pq.top() << endl; pq.pop();

} }

int main() { functionB();

}

Output?pq contains 4 elements.5 3 2 1

Summary Example #3#include <iostream> #include <queue> using namespace std;

void functionC() { priority_queue <int, vector<int>, greater<int> > pq;

pq.push(2); pq.push(5); pq.push(3); pq.push(1);

cout << "pq contains " << pq.size() << " elements.\n";

while (!pq.empty()) { cout << pq.top() << endl; pq.pop();

} }

int main() { functionC();

}

Output?pq contains 4 elements.1 2 3 5

Summary Example #4class Height { public:

Height() {}; Height(int x, int y) { feet = x; inches = y; } bool operator<(const Height&) const; int get_feet() const { return feet; } int get_inches() const { return inches; } private: int feet, inches;

};

bool Height::operator<(const Height& right) const{ return feet*12 + inches < right.feet*12 + right.inches; }

void functionD() { priority_queue <Height> pq;

Height x; x = Height(10,20); pq.push(x); x = Height(11,0); pq.push(x); x = Height(8,25); pq.push(x); x = Height(9,4); pq.push(x); cout<<"pq contains " << pq.size() << " elements.\n"; while (!pq.empty()) { cout << pq.top().get_feet() << "' " << pq.top().get_inches() << "\"" << endl; pq.pop();

} }

int main() {

functionD(); }

Output?pq contains 4 elements.10’ 20”11’ 0”8’ 25”9’ 4”

Recall: Applications of Priority Queues?

Example Applications:Unix/Linux job scheduling

Processes given a priorityTime allocated to process is based on priority of job

Priority of jobs in printer queueSortingStandby passengers at airportAuctionsStock marketEvent-driven simulationsVLSI design (channel routing, pin layout)Artificial intelligence search algorithms

Discrete Event Simulations

Here, we’re interested in procesess and systems that change at discrete instants

What are examples of discrete events?Pushing an elevator buttonStarting of a motorStopping of a motorArrival of a customerDeparture of a customerTurning on a light

These events are discrete events, because there is an instant of time at which each occurs

Are these discrete events?Train departing station

Yes

Train moving from point A to point B

No

Train arriving at point B

Yes

Note:

We can model an event of a train moving from point A to point B as two separate events (i.e., the departure and the arrival)

If we associate a time value with each discrete event, then we can model the duration of activities

Discrete Event Simulators aren’t good for continuous time

For example, not good for simulating motion of planetary bodies

Better approach?Differential equations

Note on Queuing Theory

Queuing Theory: a branch of mathematics that deals with computing (probabilistically) delays in lines at servicing points

Answer depends on:

How frequently users arrive

How long it takes to process a user once their turn arrives

Both of above typically represented as probability distribution functions

Finding solutions:

Simple cases: Can compute answer analytically

More complex cases (e.g., with k operators): Solve using discrete event simulation

The Banking SimulationWe have a bank:

Customers arrive and wait in a line until one of ktellers is availableCustomer arrival governed by probability distributionService time governed by a probability distribution

We want to know:How long (on average) does a customer have to wait?How long (on average) is the line?What is the optimal number of tellers?

Enough so that customers don’t have to wait too longNot so many that we waste our money paying tellers

The Simulation Process

Simulation consists of processing events.Here, events are:

Customer arrivingCustomer departing

Use probability distributions to generate: Input stream consisting of ordered pairs of arrival time and service time, sorted by arrival time

Then, we run the simulation for a while and collect data on:How the number of tellers impacts how long people waitHow long tellers are idle

From data, we can determine optimal number of tellers

Example of simulation process

Our system: 2 tellers, 4 customers.

Simulator generates these events:

New Person: 0 enters the bank at 1.5. Transaction time: 5.7New Person: 1 enters the bank at 2.8. Transaction time: 1.9New Person: 2 enters the bank at 3.3. Transaction time: 8.7

New Person: 3 enters the bank at 9.2. Transaction time: 2.7

based on “customer arrival” probability distribution based on “service time”

probability distribution

Simulation process, con’t.

Time 1.5: Person 0 enters bankBoth tellers are free teller 1 starts working on person 0’s transaction. (Transaction takes 5.7 minutes, so it’s done at 1.5+5.7 = 7.2)

Time 2.8: Person 1 enters bankTeller 2 is free teller 2 starts working on person 1’s transaction. (Transaction takes 1.9 minutes, so it’s done at 2.8+1.9 = 4.7)

Time 3.3: Person 2 enters bankBoth tellers are busy, so person 2 waits.

Time 4.7: Teller 2 is freeTeller 2 starts working on person 2’s transaction. (Transaction takes 8.7 minutes, so it will be done at 4.7+8.7 = 13.4)

Time 7.2: Teller 1 is free.Time 9.2: Person 3 enters bank.

Teller 1 is free, teller 1 starts working on person 3’s transaction (Transaction takes 2.7 minutes, so it will be done at 9.2+2.7 = 11.9)

Time 11.9: Teller 1 is freeTime 13.4: Teller 2 is free. No more people generated by simulation, sowe’re done.

New Person: 0 enters the bank at 1.5. Transaction time: 5.7New Person: 1 enters the bank at 2.8. Transaction time: 1.9New Person: 2 enters the bank at 3.3. Transaction time: 8.7New Person: 3 enters the bank at 9.2. Transaction time: 2.7

Analyzing data: Waiting time?Time 1.5: Person 0 enters bank

Both tellers are free teller 1 starts working on person 0’s transaction. (Transaction takes 5.7 minutes, so it’s done at 1.5+5.7 = 7.2)

Time 2.8: Person 1 enters bankTeller 2 is free teller 2 starts working on person 1’s transaction. (Transaction takes 1.9 minutes, so it’s done at 2.8+1.9 = 4.7)

Time 3.3: Person 2 enters bankBoth tellers are busy, so person 2 waits.

Time 4.7: Teller 2 is freeTeller 2 starts working on person 2’s transaction. (Transaction takes 8.7 minutes, so it will be done at 4.7+8.7 = 13.4)

Time 7.2: Teller 1 is free.Time 9.2: Person 3 enters bank.

Teller 1 is free, teller 1 starts working on person 3’s transaction (Transaction takes 2.7 minutes, so it will be done at 9.2+2.7 = 11.9)

Time 11.9: Teller 1 is freeTime 13.4: Teller 2 is free. No more people generated by simulation, sowe’re done.

Person 0: Person 2:00 0

1.4Person 1: Person 3: Average = 0.35

Analyzing data: Teller idle time?(Let’s say that bank “closes” at 12.0)

Time 1.5: Person 0 enters bankBoth tellers are free teller 1 starts working on person 0’s transaction. (Transaction takes 5.7 minutes, so it’s done at 1.5+5.7 = 7.2)

Time 2.8: Person 1 enters bankTeller 2 is free teller 2 starts working on person 1’s transaction. (Transaction takes 1.9 minutes, so it’s done at 2.8+1.9 = 4.7)

Time 3.3: Person 2 enters bankBoth tellers are busy, so person 2 waits.

Time 4.7: Teller 2 is freeTeller 2 starts working on person 2’s transaction. (Transaction takes 8.7 minutes, so it will be done at 4.7+8.7 = 13.4)

Time 7.2: Teller 1 is free.Time 9.2: Person 3 enters bank.

Teller 1 is free, teller 1 starts working on person 3’s transaction (Transaction takes 2.7 minutes, so it will be done at 9.2+2.7 = 11.9)

Time 11.9: Teller 1 is freeTime 13.4: Teller 2 is free. No more people generated by simulation, sowe’re done.

Teller 1: 1.5 + 2 + 0.1 = 3.62.8 + 0 = 2.8Teller 2: Average = 3.2

Suppose we change # tellers to 3.How does this affect waiting time?

Person 2 would get helped immediately

Time 1.5: Person 0 enters bankBoth tellers are free teller 1 starts working on person 0’s transaction. (Transaction takes 5.7 minutes, so it’s done at 1.5+5.7 = 7.2)

Time 2.8: Person 1 enters bankTeller 2 is free teller 2 starts working on person 1’s transaction. (Transaction takes 1.9 minutes, so it’s done at 2.8+1.9 = 4.7)

Time 3.3: Person 2 enters bankBoth tellers are busy, so person 2 waits.

Time 4.7: Teller 2 is freeTeller 2 starts working on person 2’s transaction. (Transaction takes 8.7 minutes, so it will be done at 4.7+8.7 = 13.4)

Time 7.2: Teller 1 is free.Time 9.2: Person 3 enters bank.

Teller 1 is free, teller 1 starts working on person 3’s transaction (Transaction takes 2.7 minutes, so it will be done at 9.2+2.7 = 11.9)

Time 11.9: Teller 1 is freeTime 13.4: Teller 2 is free. No more people generated by simulation, sowe’re done.

Average waiting time drops to 0

Suppose we change # tellers to 3.How does this affect idle time?Time 1.5: Person 0 enters bank

Both tellers are free teller 1 starts working on person 0’s transaction. (Transaction takes 5.7 minutes, so it’s done at 1.5+5.7 = 7.2)

Time 2.8: Person 1 enters bankTeller 2 is free teller 2 starts working on person 1’s transaction. (Transaction takes 1.9 minutes, so it’s done at 2.8+1.9 = 4.7)

Time 3.3: Person 2 enters bankBoth tellers are busy, so person 2 waits.

Time 4.7: Teller 2 is freeTeller 2 starts working on person 2’s transaction. (Transaction takes 8.7 minutes, so it will be done at 4.7+8.7 = 13.4)

Time 7.2: Teller 1 is free.Time 9.2: Person 3 enters bank.

Teller 1 is free, teller 1 starts working on person 3’s transaction (Transaction takes 2.7 minutes, so it will be done at 9.2+2.7 = 11.9)

Time 11.9: Teller 1 is freeTime 13.4: Teller 2 is free. No more people generated by simulation, sowe’re done.

Goes up to 5.83 (from 3.2)

Here’s the general process for discrete event simulation loop“State”: all variables that describe a system

Initialize (State)Time ← 0Initialize (futureEventSet)While (futureEventSet not empty) do:

Event ← next event in futureEventSet (i.e., deleteMin)Time ← Time (Event)State ← function of old state and eventUpdate(futureEventSet)

Generic Simulation Program:Generic Simulation Program:

Example code forhandling discrete eventsusing inheritance

Output?DEPARTURE: 3ARRIVAL: 15ARRIVAL: 35DEPARTURE: 342

#include <iostream> #include <string> #include <queue> using namespace std;

class Event { public:

Event() { time = 0; } virtual void processEvent()=0; int getTime() { return time; }

protected: int time;

};

class arrivalEvent : public Event { public:

arrivalEvent(int t) { time = t; }

void processEvent() { printf("ARRIVAL: "); }

};

class departureEvent : public Event { public:

departureEvent(int t) { time = t; }

void processEvent() { printf("DEPARTURE: "); }

};

class EventCompare { public:

bool operator()(Event* l, Event* r) { return

l->getTime() > r->getTime(); }

};

int main(void) { priority_queue <Event*,

vector<Event*>, EventCompare> pq;

arrivalEvent *a1 = new arrivalEvent(15);

arrivalEvent *a2 = new arrivalEvent(35);

departureEvent *d1 =new departureEvent(3);

departureEvent *d2 = new departureEvent(342);

pq.push(a1); pq.push(a2); pq.push(d1); pq.push(d2); while(!pq.empty()) { pq.top()->processEvent(); cout << pq.top()->getTime() << endl; pq.pop();

} }

top related