Creating a STL min heap priority queue? - c++

My task is to implement a min heap priority queue sorting each queue object with the m_time member variable.
My problem is that I can't manage the queue to sort smallest first instead of largest.
I have a struct in the .h file called Event that includes three variables:
struct Event
{
Event(int time=-1, int grind=-1, bool val=false)
{ m_time=time;m_grindNr=grind; m_value=val;}
int m_time;
int m_grindNr;
bool m_value;
};
The code below is what's inside the .cpp file:
struct compare
{
bool operator()(const Event& a, const Event& b)
{
return a.m_time < b.m_time;
}
};
void main()
{
priority_queue <Event,vector<Event>, compare> Que;
Event firstEvent;
firstEvent.m_time = 2;
firstEvent.m_grindNr = 0;
firstEvent.m_value = 0;
Que.push(firstEvent);
Event secondEvent;
secondEvent.m_time = 5;
secondEvent.m_grindNr = 0;
secondEvent.m_value = 0;
Que.push(secondEvent);
Event tempEvent = Que.top(); //Takes the top value
Que.pop();
cout << tempEvent.m_time << " "; //Should print number 2, but prints 5
tempEvent = Que.top(); //Takes the top value
Que.pop();
cout << tempEvent.m_time << endl; //Should print number 5, but prints 2
}
I have also tried using the std::less in the priority queue parameter but its the same result.
I hope you understand my question, thanks in advance.

You have to use greater, as priority_queue take largest first.
So change your compare to
return b.m_time < a.m_time;

Related

How to index array of pointers to arrays [queue]?

I am trying program a queue with arrays in C++.
I used this approach https://stackoverflow.com/a/936709/7104310 as shown below.
My question: How can I index the arrays to fill them?
In a normal 2d-array it would be arr[3][2] for example. But I do not know how to do this with pointers. The question hat not been answered in the Solution upon.
Thank you!
#include <iostream>
#define MAX_SIZE 3
using namespace std;
// ary[i][j] is then rewritten as
//arr[rear*capacity + front]
// Class for queue
class msg_queue
{
char **arr; // array to store queue elements
int capacity; // maximum capacity of the queue
int front; // front points to front element in the queue (if any)
int rear; // rear points to last element in the queue
int count; // current size of the queue
public:
msg_queue(int size = MAX_SIZE, int slot_length = MAX_SIZE); // constructor
void dequeue();
void enqueue(char x);
char peek();
int size();
bool isEmpty();
bool isFull();
};
// Constructor to initialize queue
msg_queue::msg_queue(int size, int slot_length)
{
arr = new char*[size];
for (int i = 0; i < size; ++i) {
arr[i] = new char[slot_length];
}
capacity = size;
front = 0;
rear = -1;
count = 0;
}
// Utility function to remove front element from the queue
void msg_queue::dequeue()
{
// check for queue underflow
if (isEmpty())
{
cout << "UnderFlow\nProgram Terminated\n";
exit(EXIT_FAILURE);
}
cout << "Removing " << arr[front] << '\n';
front = (front + 1) % capacity;
count--;
}
// Utility function to add an item to the queue
void msg_queue::enqueue(char item)
{
// check for queue overflow
if (isFull())
{
cout << "OverFlow\nProgram Terminated\n";
exit(EXIT_FAILURE);
}
cout << "Inserting " << item << '\n';
rear = (rear + 1) % capacity;
arr[rear] = item; //ERROR HERE
count++;
}
// Utility function to return front element in the queue
char msg_queue::peek()
{
if (isEmpty())
{
cout << "UnderFlow\nProgram Terminated\n";
exit(EXIT_FAILURE);
}
return arr[front]; //ERROR HERE
}
Well, it's still arr[3][2].
Although arrays are not pointers, the way we use them is effectively using a pointer because of the way they work and the way their name decays.
x[y] is *(x+y), by definition.
That being said, I would recommend you drop the 2D dynamic allocation (which is poison for your cache) and create one big block of Width×Height chars instead. You can use a little bit of maths to provide 2D indexes over that data.
Also you forgot to free any of that memory. If you use a nice std::vector to implement my suggested 1D data scheme (or even if you hire a vector of vectors, but ew!) then it'll be destroyed for you. Of course if you could do that then you'd probably be using std::queue…

Trouble Using Template Bubblesort with Array of Structs

So my goal is to read in some data and sort it by population, but I have to use a sort that can accept multiple data types. I was instructed to use a template to do this, but every time I pass the array "results[i].pop" to my bubblesort function I receive the error
no matching function for call to ‘bubblesort(std::string&)’
bubblesort(results[i].pop);"
note: candidate is:
election.cpp:32:3: note: template T bubblesort(T*)
T bubblesort(T ar[])
^
election.cpp:32:3: note: template argument deduction/substitution failed:
election.cpp:106:34: note: cannot convert ‘results[i].election::pop’ (type ‘std::string {aka std::basic_string}’) to type ‘std::basic_string*’
bubblesort(results[i].pop);
Here's the code:
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <fstream>
#include <stdlib.h>
using namespace std;
struct election {
string party;
string state;
string pop;
string reps;
int ratio;
};
template <typename T>
void bubblesort(T ar[])
{
//Bubblesort
int n = 51;
int swaps = 1;
while(swaps)
{
swaps = 0;
for (int i = 0; i < n - 1; i++)
{
if (ar[i] > ar[i + 1])
{
swap(ar[i],ar[i+1]);
swaps = 1;
}
}
}
//End Bubblesort
}
void delete_chars(string & st, string ch)
{
int i = st.find(ch);
while (i > -1)
{
st.replace(i,1,"");
i = st.find(ch);
}
}
int main()
{
int i = 0;
int n = 51;
election results[n];
int population[n];
int electoralVotes[n];
int ratio[n];
string st;
fstream inData;
//Read in Data from Text File
inData.open("electionresults.txt");
//Print Array as is
cout << "Array Printed As is" << endl;
cout << left << setw(10) << "Party" << setw(20) << "State" << setw(20) << "Population" << setw(15) << "Representatives" << endl;
for (int i = 0; i < n; i++)
{
getline(inData,st);
results[i].party = st.substr(0,1);
results[i].state = st.substr(8,14);
results[i].pop = st.substr(24,10);
results[i].reps = st.substr(40,2);
cout << left << setw(10) << results[i].party << setw(20) << results[i].state << setw(20) << results[i].pop << setw(15) << results[i].reps << endl;
}
//Array Sorted by Population
cout << "Array Sorted By Population" << endl;
cout << endl;
cout << endl;
cout << left << setw(10) << "Party" << setw(20) << "State" << setw(20) << "Population" << setw(15) << "Representatives" << endl;
for(int i = 0; i < n; i++){
bubblesort<string>(results[i].pop);
}
For your bubblesort to work, you need to implement the greater than operator(>) for the election struct:
struct election
{
string party;
string state;
string pop;
string reps;
int ratio;
bool operator>( election a)
{
return pop > a.pop;
}
};
Now call the bubblesort by passing the results array:
bubblesort<election>(results);
A side note your function should pass in the size rather than hardcoding the size in the function(void bubblesort(T ar[], int size)). This gives your function much more functionality and adaptability.
The other answer addressed the issue if you only wanted to sort on pop. However, it is a limited solution, and won't address the real issue of sorting on any field (today it's "pop", but what if this isn't the case tomorrow, where you want to sort on "ratio"?). The issue is that you cannot provide more than one operator > to do this and you're basically stuck only sorting on pop.
Another solution is to provide the bubblesort function with an additional template parameter that defines what to do when given two T's, whether one T should be placed before the other T in the sorted array.
#include <functional>
#include <algorithm>
//...
template <typename T, typename cmp>
void bubblesort(T ar[], int n, cmp compare_fn)
{
int swaps = 1;
while (swaps)
{
swaps = 0;
for (int i = 0; i < n - 1; i++)
{
if (!compare_fn(ar[i], ar[i + 1]))
{
std::swap(ar[i], ar[i + 1]);
swaps = 1;
}
}
}
}
// keep our original 2 param bubble sort, but let it call the one above
template <typename T>
void bubblesort(T ar[], int n)
{
// call general version using <
bubblesort(ar, n, std::less<T>());
}
We basically have two functions, where the two parameter bubblesort function calls the general 3 parameter bubblesort version that takes a third parameter, which describes the comparison.
The two parameter version of bubblesort is used when you want to call bubblesort for the "simple" cases, where your items are
In an array and
You can compare T using < and
You want to sort in ascending order (which is why we used < and not > for the general case).
For example, an array of int needs to be sorted, and you simply want to sort it in ascending order:
int someArray[10];
//...
bubblesort<int>(someArray, 10); // sort ascending
However, we don't want to do a "simple" sort on int, or even std::string. We want to sort on election, and not only that, on election.pop.
If you look at the first bubblesort function above, note that we replaced the comparison using > with a call to a function compare_fn. Note that the parameter is defaulted to the std::less function object. This is why the second bubblesort function works for simple types, since std::less uses < to compare.
However, if you tried to call the bubblesort using only two parameters using election, you come across another compiler error, basically stating that election has no operator < to compare with. The solution to that is either
1) to provide such an operator < (similar to the other answer given) to the election struct or
2) Write a custom comparison function.
So let's go over each of these solutions.
Solution 1:
If we use 1), the election struct will look like this:
struct election
{
std::string party;
std::string state;
std::string pop;
std::string reps;
int ratio;
bool operator <(const election& e) const { return pop < e.pop; }
};
int main()
{
//...
bubblesort<election>(results, n);
}
This will now sort on results using pop as the item to sort on due to the operator < defined in election being used by std::less<>.
Here is an example using overloaded < in election
However, this solution has the same issues as the other answer, in that you can only define one operator < that takes a const election& as a parameter. If you wanted to sort on ratio, for example, you're out of luck, or if you want to sort pop in descending order, you're out of luck. This is where option 2) above will be used.
Solution 2:
We can define what we want to sort on, the sort order, etc. by providing a custom comparison function, function object, or lambda function that returns true if the first T should come before the second T that's passed into the comparison function, false otherwise.
Let's try a function:
bool compare_pop(const election& e1, const election& e2)
{
return e1.pop < e2.pop; // if e1.pop comes before e2.pop, return true, else false
}
int main()
{
//...
bubblesort<election>(results, n, compare_pop);
}
What will happen now is that this will call the first version of bubblesort that takes a comparison function as a parameter. The bubblesort template function will now call compare_pop to determine if the items are out of order. If compare_pop returns false the bubblesort function will swap the items, otherwise it will leave them alone.
Here is a live example with an array of 3 elections, sorted on pop
If you wanted to use a lambda function instead of writing another compare function, that will work too:
int main()
{
//...
bubblesort<election>(results, n, [&](const element& e1, const element& e2) { return e1.pop < e2.pop; });
}
The above will do the same thing as the function example, except that you no longer need to write a separate function as the lambda syntax is used as the function.
Example using lambda syntax
So now, what if we want to sort on pop, but descending and not ascending? Simple -- call bubblesort with a different function or lambda:
bool compare_pop_up(const election& e1, const election& e2)
{
return e1.pop > e2.pop; // if e1.pop comes after e2.pop, return true, else false
}
int main()
{
//...
bubblesort<election>(results, n, compare_pop_up);
}
or using lambda:
int main()
{
//...
bubblesort<election>(results, n,
[&](const element&e1, const element& e2)
{ return e1.pop > e2.pop;});
}
and magically, the bubblesort does the job, sorting on pop in descending order.
Here is a live example with an array of 3 elections, sorted on pop, descending
What if you want to sort on ratio? Same thing -- provide a different function or lambda:
bool compare_ratio(const election& e1, const election& e2)
{
return e1.ratio < e2.ratio;
}
int main()
{
//...
bubblesort<election>(results, n, compare_ratio);
}
or using lambda:
int main()
{
//...
bubblesort<election>(results, n,
[&](const element&e1, const element& e2)
{ return e1.ratio < e2.ratio;});
}
This will sort on ratio in ascending order of the ratio.
The other issue with your code is that you are using non-standard C++ syntax in defining your arrays. You're doing this:
election results[n];
This is not standard C++ syntax, as C++ only allows arrays to be created using a compile-time expression to denote the number of items. You're using something called Variable Length Arrays, which is not standard.
Instead, you can use std::vector, which is standard C++.
#include <vector>
//...
std::vector<election> results(n);
//...
bubblesort<election>(results.data(), results.size(), compare_pop)

Seg. fault resizing array C++

I have a priority queue array that is filled with "Jobs" (name + priority). I've been able to get everything queue related working aside from re sizing if it is full. Here is the bits that I think are causing a segmentation fault that I haven't been able to figure out.
EDIT:
Here is a bit more code that will compile, I left in the rest of the functions in case those might help in any way. Right now the initial capacity is set to 5, when you try to add a job to the full list it will double the capacity of the array and allow you to add a couple more jobs before a SEG. fault.
pq.h
#ifndef PQ_H
#define PQ_H
#include "interface.h"
#include <string>
using namespace std;
class Job {
public:
int getPriority();
string getTaskName();
void setPriority(int val);
void setTaskName(string tname);
Job();
private:
int priority;
string taskName;
};
class PriorityQueue {
public:
PriorityQueue();
~PriorityQueue();
int size();
bool isEmpty();
void clear();
void enqueue(string value, int priority);
string dequeue();
string peek();
int peekPriority();
PriorityQueue(const PriorityQueue & src);
PriorityQueue & operator=(const PriorityQueue & src);
private:
static const int INITIAL_CAPACITY = 5;
Job *array;
int count;
int capacity;
void expandCapacity() {
Job *oldArray = array;
capacity *= 2;
array = new Job[capacity];
for (int i = 0; i < count; i++) {
array[i] = oldArray[i];
}
delete[] oldArray;
}
};
#endif
pq.cpp
#include <iostream>
#include <cstring>
using namespace std;
//#include "job.h"
#include "pq.h"
Job::Job() // Constructor
{
priority= 0;
taskName = "There are no items in the list.";
}
int Job::getPriority(){ // returns the prority of the job
return priority;
}
string Job::getTaskName(){ // returns the name of the job
return taskName;
}
void Job::setPriority(int val){ // sets the priority of a newly created job
priority = val;
}
void Job::setTaskName(string tname){ // sets the name of a new job
taskName = tname;
}
PriorityQueue::PriorityQueue() // constructor
{
count = 0;
capacity = INITIAL_CAPACITY - 1;
array = new Job[INITIAL_CAPACITY];
}
PriorityQueue::~PriorityQueue() { // destructor
delete [] array;
}
int PriorityQueue::size() { // returns the number of jobs in the queue
return count;
}
bool PriorityQueue::isEmpty() { // returns true if queue is empty
if (count != 0){
return false;
}else{
return true;
}
}
void PriorityQueue::clear() { // clears queue of all jobs
count = 0;
// need to make it remove and delete the items
}
void PriorityQueue::enqueue(string value, int priority) {
// tests size to see if Queue is a max capacity
if(count == capacity){
expandCapacity();
cout << "\tList was full and has been expanded\n";
}
array[++count].setPriority(priority);
array[count].setTaskName(value);
// upheap operations
Job v = array[count];
int tempcount = count;
while (array[tempcount/2].getPriority() >= v.getPriority()){
array[tempcount] = array[tempcount/2];
tempcount = tempcount/2;
array[tempcount] = v;
}
}
string PriorityQueue::dequeue() {
// removes the job with the highest priority from the queue and returns the name
if(this->isEmpty()){ // make sure the queue isnt empty
string empty = "The queue is empty";
return empty;
}else{
Job remove = array[1];
array[1] = array[count--];
int j;
Job v;
int k = 1;
v = array[k];
while(k <= count/2){
cout << "dequeuewhile"; // test
j = k + k;
if(j < count && array[j].getPriority() > array[j+1].getPriority()){
j++;
cout << "dequeueloop if1"; // test
}
if(v.getPriority() <= array[j].getPriority()){
cout << "dequeueloop if2"; //test
break;
}
array[k] = array[j];
k = j;
}
array[k] = v;
return remove.getTaskName(); // returns the name of the removed job
}
}
string PriorityQueue::peek() { // returns the name of the highest priority job without removing it from the queue
if(count == 0){
return array[0].getTaskName();
}
return array[1].getTaskName();
}
int PriorityQueue::peekPriority() { // returns the priority from the highest priority job without removing it from the queue
if(count == 0){
cout << "\tThere are no items in the list.\n";
return array[0].getPriority();
}
return array[1].getPriority();
}
I think that when you do ++count, the next use of count will be out of bounds for the array.
array[++count].setPriority(priority);
// SEGMENTATION FAULT HERE
array[count].setTaskName(value);
If the capacity of the array is 5, and count was 4, then you just incremented count to 5, and tried to access element 5, which is out-of-bounds.
array = new Job[capacity];
for (int i = 0; i < count; i++) {
array[i] = oldArray[i];
}
Lets assume capacity is 10, so you've got an array of 10 elements, ranging from elements 0 to 9.
counttells us how many elements are being used.
If count happens to be 9, then when you increment count by one, it is now 10. Then, when line come you marked as producing segment fault comes, you're trying to access element 10, in our example. There is no element 10in an array of length 10, so you're out of bounds.
array[++count].setPriority(priority); // array[10], but last element is 9!
// SEGMENTATION FAULT HERE
array[count].setTaskName(value); // array[10], but last element is 9!
And, of course, everything after that part causes the same issue, as you keep using array[count].
Your original code did exactly as the previous answer given by #antiHUMAN.
The problem you're having is mixing or erroneously using 0-based and 1-based concepts.
Your first mistake is to make capacity a 0-based number. The capacity should denote the maximum number of items in an array, thus you should not be subtracting 1 from it. If the array can hold 5 items, then capacity should be 5, not 4.
PriorityQueue::PriorityQueue() // constructor
{
count = 0;
capacity = INITIAL_CAPACITY; // this remains 1-based.
array = new Job[INITIAL_CAPACITY];
}
or using the initializer-list:
PriorityQueue::PriorityQueue() : count(0),
capacity(INITIAL_CAPACITY),
array(new Job[INITIAL_CAPACITY]) {}
The 0-based number in your situation should be count, not capacity. Given that, since count is 0-based, and capacity is 1-based, your test in enqueue needs to be changed:
if(count + 1 == capacity){
expandCapacity();
cout << "\tList was full and has been expanded\n";
}
Note that 1 is added to count to account for the fact that count is 0-based and capacity is 1 based.

Class method returns last made of class, C++

So for school I have to make a Node class that holds a time and a number (it's used for an insertion sort later). I'm still new to C++ so I'm probably doing something wrong here, but whenever I call my GetNumber() method, it will return only the number of the last Node that was made. My code is below:
Node.cpp
#include "Node.h"
int n, t;
Node::Node(int number, int time)
{
n = number;
t = time;
}
Node::~Node(void)
{
}
int Node::GetTime(void)
{
return t;
}
int Node::GetNumber(void)
{
return n;
}
And in main:
Node f(123, GetTickCount());
for (int i = 0; i < 1000; i++){}
Node g(124, GetTickCount());
for (int i = 0; i < 1000; i++){}
Node d(111, GetTickCount());
cout << f.GetNumber() << " " << f.GetTime()<<endl;
cout << g.GetNumber() << " " << g.GetTime()<<endl;
cout << d.GetNumber() << " " << d.GetTime()<<endl;
And the output:
111 168921894
111 168921894
111 168921894
int n, t;
You are declaring n and t as global variables - they don't belong to any particular object. All Nodes will see the same n and t objects.
You should be declaring these as members of Node:
class Node {
// ...
int n, t;
// ...
};
The problem here is you are using file level variables as the storage for all Node values. Instead you need to store them as instance fields in the type
class Node {
...
private:
int n;
int t;
};
Once those fields are defined delete the declaration at the top of the file for n and t
You didn't define "n" and "t" in the class and so they are global and only the last one to change is the one that is relevant.

Priority Queue Wrong Order

I am programming the huffman encoding. This is the beginning of my program:
using namespace std;
//Counting methods
int *CountCharOccurence(string text)
{
int *charOccurrence = new int[127];
for(int i = 0; i < text.length(); i++)
{
charOccurrence[text[i]]++;
}
return charOccurrence;
}
void DisplayCharOccurence(int *charOccurrence)
{
for(int i = 0; i < 127; i++)
{
if(charOccurrence[i] > 0)
{
cout << (char)i << ": " << charOccurrence[i] << endl;
}
}
}
//Node struct
struct Node
{
public:
char character;
int occurrence;
Node(char c, int occ) {
character = c;
occurrence = occ;
}
bool operator < (const Node* node)
{
return (occurrence < node->occurrence);
}
};
void CreateHuffmanTree(int *charOccurrence)
{
priority_queue<Node*, vector<Node*> > pq;
for(int i = 0; i < 127; i++)
{
if(charOccurrence[i])
{
Node* node = new Node((char)i, charOccurrence[i]);
pq.push(node);
}
}
//Test
while(!pq.empty())
{
cout << "peek: " << pq.top()->character << pq.top()->occurrence << endl;
pq.pop();
}
}
int main(int argc, char** argv) {
int *occurrenceArray;
occurrenceArray = CountCharOccurence("SUSIE SAYS IT IS EASY");
DisplayCharOccurence(occurrenceArray);
CreateHuffmanTree(occurrenceArray);
return (EXIT_SUCCESS);
}
The program first outputs the characters with their occurence number. This looks fine:
: 4
A: 2
E: 2
I: 3
S: 6
T: 1
U: 1
Y: 2
but the test loop which has to display the node contents in priority order outputs this:
peek: Y2
peek: U1
peek: S6
peek: T1
peek: I3
peek: E2
peek: 4
peek: A2
This is not the expected order. Why?
Elements in your priority queue are pointers. Since you don't provide a function that takes 2 pointers to Node objects , default compare function compares 2 pointers.
bool compareNodes(Node* val1, Node* val2)
{
return val1->occurence < val2->occurence;
}
priority_queue<Node*, vector<Node*>,compareNodes > pq;
Your operator < is used when Node compares with Node*
You should tell your priority queue what it should sort by. In your case, you have to tell it to sort by Node::occurence.
You are storing pointers to nodes in the queue, but haven't provided a suitable comparison function, so they are sorted by comparing the pointers. The operator< you've provided will compare a node with a pointer, which isn't what you want.
There are two options:
Provide a function for comparing two node pointers according to their values, and give this function to the queue, or
Store node objects in the queue, and provide an operator< to compare two nodes.
The second option will also fix the memory leak in your code, and remove a whole pile of unnecessary memory allocations, so I would suggest that.