Starting from:
$30

$24

Programming Assignment 7 Priority Queue (Heap)

CSCE 221  


Programming Assignment 7 Priority Queue (Heap)

 

<functional>

<deque>

<initializer_list>

<iostream>

<sstream>

<stdexcept>

<vector>

"heap.h"

"priority_queue.h"


Code Coverage

You must submit a test suite for each task that, when run, covers at least 90% of your code. You should, at a minimum, invoke every function at least once. Best practice is to also check the actual behavior against the expected behavior, e.g. verify that the result is correct. You should be able to do this automatically, i.e. write a program that checks the actual behavior against the expected behavior.

Your test suite should include ALL tests that you wrote and used, including tests you used for debugging.

You should have MANY tests.


Starter Code

for X in {heap, priority_queue}

X.h

X_tests.cpp

X_compile_test.cpp

Makefile


Files to Submit

heap.h

heap_tests.cpp

priority_queue.h

priority_queue_tests.cpp
CSCE 221  


Task 1: Heap

Implement stand-alone heap methods: heapify, insert, get_min, and delete_min.

Requirements

Files

heap.h - contains the template definitions

heap_tests.cpp - contains the test cases and test driver (main)

Functions

The Container type must satisfy the requirements of SequenceContainer, and its iterators must satisfy the requirements of LegacyRandomAccessIterator. Additionally, it must provide the following functions with the usual semantics:

    • front()

    • push_back()

    • pop_back()

The standard containers std::vector and std::deque satisfy these requirements.

template <class Container, class Compare=std::less<typename Container::value_type>>

void heapify(Container*, Compare <var name> =std::less<typename Container::value_type>{}) - build a heap with the data in the given container (passed by pointer value to indicate that this function modifies the container) using the specified comparator (comparison functor, default is std::less to make a min heap), the first element of the heap should be in index 1.

template <class Container, class Compare=std::less<typename Container::value_type>>

void heap_insert(Container*, const typename Container::value_type&, Compare=std::less<typename Container::value_type>{}) - insert the specified value into the specified heap (passed by pointer value to indicate that this function modifies the container, which is assumed to already be in heap order with first element in index 1) using the specified comparator (default std::less for a min heap). If the container is empty, do the user a solid and make it a heap before inserting.

template <class Container>

const typename Container::value_type& heap_get_min(const Container&) - return the “minimum” value (whichever value is at the root of the heap) in the specified heap (which is passed by constant reference to indicate that this function does not modify the container). Throw std::invalid_argument if the heap is empty.

template <class Container, class Compare=std::less<typename Container::value_type>>
CSCE 221  


void heap_delete_min(Container*, Compare=std::less<typename Container::value_type>{}) - remove the “minimum” value (whichever value is at the root of the heap) in the specified heap (passed by pointer value to indicate that this function modifies the container, which is assumed to already be in heap order with first element in index 1) using the specified comparator (default std::less for a min heap). Throw std::invalid_argument if the heap is empty.


Optional

template <class Container, class Compare=std::less<typename Container::value_type>>

void heapify(Container&, Compare=std::less<typename Container::value_type>{}) - wrapper function for heapify if you have difficulty remembering to pass by pointer value, sends the address of the container on to the actual function.

template <class Container, class Compare=std::less<typename Container::value_type>>

void heap_insert(Container&, const typename Container::value_type&, Compare=std::less<typename Container::value_type>{}) - wrapper function for insert if you have difficulty remembering to pass by pointer value, sends the address of the container on to the actual function.

template <class Container, class Compare=std::less<typename Container::value_type>>

void heap_delete_min(Container&, Compare=std::less<typename

Container::value_type>{}) - wrapper function for delete_min if you have difficulty remembering to pass by pointer value, sends the address of the container on to the actual function. Throw std::invalid_argument if the heap is empty.
CSCE 221  


Example

std::vector<int> heap{150,80,40,30,10,70,110,100,20,90,60,50,120,140,130};

std::cout << "before heapify: ";

for (int i : heap) { std::cout << i << " "; } std::cout << std::endl;

heapify(&heap);

std::cout << "after heapify: ";

for (int i : heap) { std::cout << i << " "; } std::cout << std::endl;

for (unsigned j = 0; j < 4; j++) {

std::cout << "minimum is " << heap_get_min(heap) << std::endl;

std::cout << "delete min" << std::endl;

heap_delete_min(&heap);

std::cout << "heap: ";

for (int i : heap) { std::cout << i << " "; } std::cout << std::endl;
}

int values[] = {47,54,57,43,120,3};

for (unsigned j = 0; j < 6; j++) {

std::cout << "insert " << values[j] << std::endl; heap_insert(&heap, values[j]);

std::cout << "heap: ";

for (int i : heap) { std::cout << i << " "; } std::cout << std::endl;

}
CSCE 221  


Example Output

Note about the “after heapify” lines: value in index 0 is unimportant (index 0 is not used, shown here only for completeness and example).

before heapify: 150 80 40 30 10 70 110 100 20 90 60 50 120 140 130

after heapify: 0 10 20 40 30 60 50 110 100 150 90 80 70 120 140 130

minimum is 10

delete min

heap: 0 20 30 40 100 60 50 110 130 150 90 80 70 120 140

minimum is 20

delete min

heap: 0 30 60 40 100 80 50 110 130 150 90 140 70 120

minimum is 30

delete min

heap: 0 40 60 50 100 80 70 110 130 150 90 140 120

minimum is 40

delete min

heap: 0 50 60 70 100 80 120 110 130 150 90 140 insert 47

heap: 0 47 60 50 100 80 70 110 130 150 90 140 120 insert 54

heap: 0 47 60 50 100 80 54 110 130 150 90 140 120 70 insert 57
heap: 0 47 60 50 100 80 54 57 130 150 90 140 120 70 110 insert 43

heap: 0 43 60 47 100 80 54 50 130 150 90 140 120 70 110 57 insert 120

heap: 0 43 60 47 100 80 54 50 120 150 90 140 120 70 110 57 130 insert 3

heap: 0 3 43 47 60 80 54 50 100 150 90 140 120 70 110 57 130 120
CSCE 221  


Task 2: Priority Queue

Implement a priority queue using the heap functions from Task 1.

Requirements

Files

priority_queue.h - contains the template definitions

priority_queue_tests.cpp - contains the test cases and test driver (main)

Class

template <class Comparable, class Container=std::vector<Comparable>, class Compare=std::less<typename Container::value_type>> class PriorityQueue;

Note: Read the compile test to see how to properly instantiate the class. Basically, the declaration looks like

PriorityQueue<T, std::vector<T>, std::less<T>> priority_queue;

which default constructs a priority queue of T values using a std::vector that holds T values and the std::less comparator which compares T values using “strictly less” (<). If you want to use a different value type, or a different container type, or a different comparator type, you change those in the template arguments (between the angle brackets: < … >). You put the values of the container and comparator you want to use into the arguments to the constructor:

PriorityQueue<T, std::vector<T>, std::less<T>> priority_queue(compare, container);

where compare is a std::less<T> object and container is a std::vector<T> object.

The types of the constructor arguments and the types in the template arguments must match.

Functions (public)

Constructors

PriorityQueue() - makes an empty priority queue using the default container (std::vector) and default comparator (std::less).

explicit PriorityQueue(const Compare&) - makes an empty priority queue using the default container (std::vector) and specified comparator.
explicit PriorityQueue(const Container&) - makes a priority queue using the specified container (which may not be empty and is not a heap) and default comparator (std::less). PriorityQueue(const Compare&, const Container&) - makes a priority queue using the specified container (which may not be empty and is not a heap) and the specified comparator.
CSCE 221  


Iterators

Optional

Element Access

typename Container::const_reference top() const - return the top of this priority queue.

Throw std::invalid argument if the queue is empty.

Capacity

bool empty() const - returns true if this priority queue is empty

size_t size() const - returns the number of values in this priority queue

Modifiers

void make_empty() - remove all values from this priority queue

void push(const typename Container::value_type&) - insert the given lvalue reference into this priority queue

void pop() - remove the top of this priority queue. Does not throw any exceptions.

Visualization

void print_queue(std::ostream&=std::cout) const - pretty print the queue as a comma-and-space separated list of values to the specified output stream (default std::cout), prints “<empty>\n” if this priority queue is empty. E.g. 1, 2, 4, 3, 6, 5, 11

“Optional” - They must work correctly but that doesn’t mean you have to implement them

PriorityQueue(const PriorityQueue&) - constructs a copy of the specified priority queue (using same container type and comparator)

~PriorityQueue() - destroys this priority queue.

PriorityQueue& operator=(const PriorityQueue&) - assigns this priority queue to be a copy of the specified priority queue (with the same container type and comparator)


Optional for Real - not tested

PriorityQueue(const Compare& compare, Container&& container) - move constructs a priority queue using the specified comparator and container.

PriorityQueue(PriorityQueue&&) - move constructs a copy of the specified priority queue (using same container type and comparator)

PriorityQueue& operator=(PriorityQueue&&) - move assigns this priority queue to be a copy of the specified priority queue (with the same container type and comparator)
void push(typename Container::value_type&&) - insert the given value into this priority queue using move semantics
CSCE 221  


Example

std::cout << "SELECTION PROBLEM" << std::endl;

std::cout << "make a priority queue from N = 168 elements in O(N) time" << std::endl;
std::vector<int> values{509, 887, 53, 739, 491, 307, 727, 223, 919, 263, 983, 7, 809, 353, 659, 769, 173, 431, 619, 139, 2, 3, 181, 23, 283, 617, 463, 757, 89, 541, 997, 743, 907, 13, 337, 349, 523, 857, 97, 827, 661, 67, 373, 59, 11, 277, 379, 19, 941, 607, 367, 101, 457, 929, 599, 971, 967, 647, 71, 991, 211, 467, 881, 137, 311, 673, 197, 179, 859, 239, 233, 631, 449, 281, 499, 269, 877, 421, 419, 613, 593, 383, 937, 569, 487, 839, 479, 461, 683, 653, 227, 61, 107, 113, 947, 191, 103, 313, 733, 151, 257, 73, 821, 547, 521, 691, 83, 823, 443, 31, 5, 643, 131, 389, 571, 163, 271, 601, 359, 199, 853, 29, 167, 557, 157, 193, 977, 37, 41, 773, 347, 709, 251, 331, 829, 503, 409, 719, 397, 241, 47, 641, 787, 863, 109, 587, 17, 751, 229, 911, 811, 317, 563, 701, 797, 953, 293, 149, 439, 127, 883, 577, 79, 433, 43, 761, 401, 677}; PriorityQueue<int> pq(values);

std::cout << "pop k = 42 = O(N / log N) elements in O(k log N) = O(N) time" << std::endl;

for (int i = 0; i < 41; i++) { pq.pop(); }

// ^^^ pops 41, top is would-be 42nd pop vvvvv

std::cout << "found k-th smallest element = " << pq.top() << " in O(N + k log N)= O(N) time" << std::endl;

std::cout << std::endl << "INTERMISSION" << std::endl;

std::cout << "empty the queue in O(1) time" << std::endl; pq.make_empty();

std::cout << std::endl << "DISCRETE EVENT SIMULATION" << std::endl; int t = 0;

size_t busy_start = 0, busy_stop = 0, busy_time = 0, wait_time = 0, cnt = 0,

cust_id = 0, next = 7;

bool busy = false;

std::list<size_t> line;

pq.push(t);

while (!pq.empty()) {

t = pq.top();

pq.pop();

if (t%2) {

// departure

std::cout << "customer departed at time " << t << std::endl; cnt++;
if (line.empty()) {
CSCE 221  


busy = false;

busy_stop = t;

busy_time += busy_stop - busy_start;

} else {

        ◦ next in line

int arrival_time = line.front();

line.pop_front();

wait_time += (t - arrival_time);

std::cout << "next customer in line has been waiting " << (t - arrival_time) << " time units" << std::endl;

// schedule departure at odd time (t is odd right now), >0 from

now

int service_time = 2*((next+3)%5)+2;

pq.push(t + service_time);

next = (next+5)%11;

}

} else {

        ◦ arrival

std::cout << "customer " << ++cust_id << " arrived at time " << t << std::endl;
if (cust_id < 10) {

    • schedule next arrival at even time (t is even right now) int interarrival_time = 2*((next+3)%5)+2;
pq.push(t + interarrival_time); next = (next+5)%11;

}

if (busy) {

    • wait in line

line.push_back(t);

std::cout << "  server is busy, customer must wait in line, there

are " << line.size() << " in line" << std::endl;

} else {

        ◦ serve busy = true; busy_start = t;

std::cout << "  service begins immediately" << std::endl;

        ◦ schedule departure at odd time (t is even right now), >0 from

now

int service_time = 2*((next+3)%5) + 1;

pq.push(t + service_time);

next = (next+5)%11;

}

}

}
CSCE 221  


std::cout << "end of simulation\n-----------------" << std::endl;

std::cout << "served 10 customers in " << t << " time units" << std::endl; std::cout << "server was busy for " << busy_time << " total time units" << std::endl;

std::cout << "customers waited " << wait_time << " total time units" << std::endl;

Example Output

SELECTION PROBLEM

make a priority queue from N = 168 elements in O(N) time pop k = 42 = O(N / log N) elements in O(k log N) = O(N) time found k-th smallest element = 181 in O(N + k log N)= O(N) time

INTERMISSION

empty the queue in O(1) time

DISCRETE
EVENT SIMULATION


customer
1
arrived at
time

0
service begins immediately
customer
2
arrived at
time

2
server
is busy, customer

must wait in line, there are 1 in line
customer
departed at time
9

next customer in line
has
been waiting 7 time units
customer
3
arrived at
time

12
server
is busy, customer

must wait in line, there are 1 in line
customer
departed at time
17
next customer in line
has
been waiting 5 time units
customer
4
arrived at
time

20
server
is busy, customer

must wait in line, there are 1 in line
customer
departed at time
25
next customer in line
has
been waiting 5 time units
customer
5
arrived at
time

26
server
is busy, customer

must wait in line, there are 1 in line
customer
6
arrived at
time

30
server
is busy, customer

must wait in line, there are 2 in line
customer
departed at time
31
next customer in line
has
been waiting 5 time units
customer
departed at time
33
next customer in line
has
been waiting 3 time units
customer
7
arrived at
time

34
server
is busy, customer

must wait in line, there are 1 in line
customer
departed at time
35
next customer in line
has
been waiting 1 time units
customer
8
arrived at
time

44
CSCE 221  


server is busy, customer must wait in line, there are 1 in line customer departed at time 45

next customer in line has been waiting 1 time units customer 9 arrived at time 52

server is busy, customer must wait in line, there are 1 in line customer departed at time 53
next customer in line has been waiting 1 time units customer departed at time 59 customer 10 arrived at time 60

service begins immediately

customer departed at time 65

end of simulation

-----------------

served 10 customers in 65 time units

server was busy for 64 total time units

customers waited 28 total time units


The beauty of generic programming (templates) is that you don't have to know the specific types of parameters (or that you actually do know, but it's a generic type). Look:

template <class Container,

class Compare=std::less<typename Container::value_type>>

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You see that part (bold, underlined by ^s)? That's the type of object that is in the container, e.g. int or std::string or whatever.

We can make one those: typename Container::value_type value;

So, if the container is holding ints, this is just int value;

If the container is holding std::strings, this is just std::string value;

If you want an anonymous value (i.e. rvalue reference): typename Container::value_type{}

More products