Hanoi Iterative solution - c++

I am attempting to implement the Tower of Hanoi iterative solution in c++ as noted in Wikepedia
Simpler statement of iterative solution
Alternating between the smallest and the next-smallest disks, follow the steps for the appropriate case:
For an even number of disks:
*make the legal move between pegs A and B*
*make the legal move between pegs A and C*
*make the legal move between pegs B and C*
*repeat until complete*
For an odd number of disks:
*make the legal move between pegs A and C*
*make the legal move between pegs A and B*
*make the legal move between pegs C and B*
*repeat until complete*
In each case, a total of 2n-1 moves are made.
The code I have written thus far is
#include <iostream>
#include <list>
const int SIZE = 5;
int pCount = 1;
using namespace std;
list<int> *lhs;
list<int> *mid;
list<int> *rhs;
void initTower(int size);
void printPeg(list<int> p);
bool printTower();
bool isEven(list<int> l);
bool move(list<int> *from, list<int> *to);
int main() {
lhs = new list<int>;
mid = new list<int>;
rhs = new list<int>;
initTower(SIZE);
printTower();
bool run = true;
while (run) {
int n = SIZE;
if (n % 2 == 0) // even
{
move(lhs,mid);
move(lhs,rhs);
move(mid,rhs);
}else{
move(lhs,rhs);
move(lhs,mid);
move(rhs,mid);
}
if (rhs->size() == SIZE) {
run = false;
}
}
return 0;
}
bool isEven(list<int> l) {
return l.size() % 2 == 0;
}
void initTower(int size) {
while (size--)
lhs->push_back(size + 1);
}
void printPeg(list<int> p) {
if (p.empty()) {
cout << "empty" << endl;
} else {
for (int i: p)
cout << i << " ";
cout << endl;
}
}
bool printTower() {
cout << "==============" << endl;
cout << "=====top=======" << pCount++ << endl;
printPeg(*lhs);
printPeg(*mid);
printPeg(*rhs);
cout << "==============" << endl << endl;
return true;
}
bool move(list<int> *from, list<int> *to) {
bool vailidMove = false;
int fVal = 0;
int toVal = 0;
if (!from->empty())
fVal = from->back();
if (!to->empty())
toVal = to->back();
if ((fVal < toVal || toVal == 0) && (fVal > 0 && fVal != 0)) {
from->pop_back();
to->push_back(fVal);
vailidMove = true;
printTower();
}
return vailidMove;
}
my output to the above program is.
==============
=====top=======1
5 4 3 2 1
empty
empty
==============
==============
=====top=======2
5 4 3 2
empty
1
==============
==============
=====top=======3
5 4 3
2
1
==============
==============
=====top=======4
5 4 3
2 1
empty
==============
==============
=====top=======5
5 4
2 1
3
==============
What am I overlooking? Any advise is helpful.

I added one condition in your move function to move poles if fVal > toVal (or you would stop instead of finishing the algorithm).
I alternated the source and destination half the time, as this is said in the wiki article you were referring to.
Alternating between the smallest and the next-smallest disks
I also changed the pCount initialization to 0 instead of 1 as the first print only list the starting tower and is not an operation. But you may put 1 again if that if what you wanted.
PS: I tested this code and it works perfectly fine, giving 2^n-1 operations like it is supposed to.
#include <iostream>
#include <list>
const int SIZE = 12;
int pCount = 0;
using namespace std;
list<int> *lhs;
list<int> *mid;
list<int> *rhs;
void initTower(int size);
void printPeg(list<int> p);
bool printTower();
bool isEven(list<int> l);
bool move(list<int> *from, list<int> *to);
int main() {
lhs = new list<int>;
mid = new list<int>;
rhs = new list<int>;
initTower(SIZE);
printTower();
bool run = true;
bool lowest = false;
while (run) {
lowest = !lowest;
int n = SIZE;
if (n % 2 == 0) // even
{
if (lowest){
move(lhs,mid);
if (rhs->size() == SIZE) {
break;
}
move(lhs,rhs);
move(mid,rhs);
}else{
move(mid,lhs);
if (rhs->size() == SIZE) {
break;
}
move(rhs,lhs);
move(rhs,mid);
}
}else{
if (lowest){
move(lhs,rhs);
move(lhs,mid);
if (rhs->size() == SIZE) {
break;
}
move(mid,rhs);
}else{
move(rhs,lhs);
move(mid,lhs);
if (rhs->size() == SIZE) {
break;
}
move(rhs,mid);
}
}
lowest = !lowest;
}
return 0;
}
bool isEven(list<int> l) {
return l.size() % 2 == 0;
}
void initTower(int size) {
while (size--)
lhs->push_back(size + 1);
}
void printPeg(list<int> p) {
if (p.empty()) {
cout << "empty" << endl;
} else {
for (int i: p)
cout << i << " ";
cout << endl;
}
}
bool printTower() {
cout << "==============" << endl;
cout << "=====top=======" << pCount++ << endl;
printPeg(*lhs);
printPeg(*mid);
printPeg(*rhs);
cout << "==============" << endl << endl;
return true;
}
bool move(list<int> *from, list<int> *to) {
bool vailidMove = false;
int fVal = 0;
int toVal = 0;
if (!from->empty())
fVal = from->back();
if (!to->empty())
toVal = to->back();
if ((fVal < toVal || toVal == 0) && fVal > 0) {
from->pop_back();
to->push_back(fVal);
vailidMove = true;
printTower();
}else if ((fVal > toVal || fVal == 0) && (toVal > 0 && toVal != 0)) {
from->push_back(toVal);
to->pop_back();
vailidMove = true;
printTower();
}
return vailidMove;
}

Related

Heap corruption detected in dynamicDataHolder | C++

After I run this program, and input the Value: value in main(), I get the error "HEAP CORRUPTION DETECTED":
I've spent about an hour trying to figure out what's causing this, would appreciate help in what caused this and what exactly I need to do to fix this.
Thanks!
#include <iostream>
using namespace std;
template <class t>
class dynamicDataHolder
{
t* ptr = NULL;
int size = 0;
int elements = 0;
public:
dynamicDataHolder() {
ptr = new t[5];
size = 5;
elements = 0;
}
dynamicDataHolder(int arraySize) {
ptr = new t[size];
size = arraySize;
elements = 0;
}
dynamicDataHolder(const dynamicDataHolder<t>& obj) {
ptr = new t[obj.size];
if (ptr != NULL) {
for (int i = 0; i < obj.size; i++) {
ptr[i] = obj.ptr[i];
}
}
else {
cout << "\nPointer to the holder was found to be NULL." << endl;
}
elements = obj.elements;
size = obj.size;
}
t getData(int pos) {
if (pos < 0 || pos > size)
{
cout << "\nError: Invalid index!" << endl;
return 0;
}
return ptr[pos];
}
int sizeA() {
return size;
}
int capacity() {
int capacity = size - elements;
return capacity;
}
void insert(t data) {
int pos;
if (elements >= size) {
int updatedSize = (2 * size);
t* tempPtr = ptr;
ptr = new t[updatedSize];
for (int i = 0; i < size; ++i) {
ptr[i] = tempPtr[i];
}
delete[] tempPtr;
tempPtr = NULL;
size = updatedSize;
pos = elements;
ptr[pos] = data;
incrementElement();
}
else {
if (elements == 0) {
pos = 0;
ptr[pos] = data;
incrementElement();
}
else {
pos = elements;
ptr[pos] = data;
incrementElement();
}
}
}
bool compare(const dynamicDataHolder<t>& obj)
{
bool result = false;
if (obj.size != size || obj.elements != elements) {
return result;
}
for (int i = 0; i < size; i++) {
result = false;
if (ptr[i] == obj.ptr[i])
{
result = true;
}
}
return result;
}
void resize(int updatedSize) {
t* tempPtr = ptr;
ptr = new t[updatedSize];
if (updatedSize < size) {
cout << "\nWarning! Entered size is less than the current size." << endl
<< "Loss of data may occur. Continue? (Y/N)" << endl;
Select:
char userChoice; cin >> userChoice;
if (userChoice == 'y' || userChoice == 'Y') {
goto Continue;
}
else if (userChoice == 'n' || userChoice == 'N') {
return;
}
else {
cout << "\nInvalid selection - please try again." << endl;
goto Select;
}
}
Continue:
if (ptr != NULL) {
for (int i = 0; i < size; i++) {
ptr[i] = tempPtr[i];
}
delete[] tempPtr;
tempPtr = NULL;
size = updatedSize;
}
else {
cout << "\nPointer to the holder was found to be NULL." << endl;
}
}
void insertAtNthPos()
{
cout << "\nEnter the details below to insert values:-\n" << endl;
cout << "\nPosition: ";
int pos = 0; cin >> pos;
cout << "Value: ";
t value; cin >> value;
if (pos <= size)
{
ptr[pos] = value;
if (pos > elements) {
incrementElement();
}
}
else {
resize(2 * size);
ptr[pos] = value;
incrementElement();
}
}
dynamicDataHolder& operator=(const dynamicDataHolder& rhs) {
delete[] ptr;
ptr = new t[rhs.size];
if (this != &rhs)
{
for (int i = 0; i < rhs.size; i++)
{
ptr[i] = rhs.ptr[i];
}
}
return *this;
}
~dynamicDataHolder()
{
delete[] ptr;
ptr = NULL;
}
void incrementElement()
{
elements += 1;
}
};
int main()
{
cout << "What do you want to do?" << endl
<< "\t1. Run Test Sequence" << endl
<< "\t0. Exit Program" << endl;
Select:
int userChoice = 0; cin >> userChoice;
if (userChoice == 1) {
goto testSequence;
}
else if (userChoice == 0) {
return 0;
}
else {
cout << "\nInvalid selection - please try again." << endl;
goto Select;
}
testSequence:
system("CLS");
dynamicDataHolder<int> obj;
dynamicDataHolder<char> obj2(5);
dynamicDataHolder<char> obj3 = obj2;
bool result = (obj3.compare(obj2));
if (result == 1) {
cout << "True" << endl;
}
else {
cout << "\nFalse" << endl;
}
for (int i = 0; i < 5; i++) {
obj.insert(i * 2);
}
cout << "Capacity: " << obj.capacity() << endl;
cout << "Size: " << obj.sizeA() << endl;
obj.resize(15);
cout << obj2.getData(4) << endl;
obj2.insertAtNthPos();
dynamicDataHolder<int> obj4;
obj4 = obj;
}
Free code review.
Here's a simplified version of your code
replacing goto with loops (this revolution in language development happened in 1970, get with the times!)
use the right names! Naming is important.
In particular
capacity means "limit to potential size" (what you names "size" or "arraySize" before)
size means "count of elements in the collection" (e.g. size grows on insertion)
(capacity - size) is free space/room/available capacity. This is what you named "capacity" before
Violating expectations of identifier meanings leads to bugs. In fact, you had that, because your own test sequence used getData(4) on a holder that contained 0 elements (_size == 0).
Same for operations. insert(...) should insert, not overwrite (see below), resize(...) should change the size, not the capacity.
To change the capacity, the standard library uses the term reserve(...), which I also used for consistency and least-surprise.
Also, names should be descriptive. In a strong typed language naming the variable after its type is redundant information. Also, you can names variables strA, strB, strC but it's more informative to name them givenName, middleNames, surName. Note that suddenly we have semantic information (is it lastName, surName, birthName, familyName. So much information is conveyed).
In this sense, I renamed ptr to _data
While we're at it, we might rename the class to be descriptive: DynaArray<T> tells you more than dynamicDataHolder<T> (that could be std::optional<T>, std::unique_ptr<T>, std::vector<T>, harddiskVolume etc).
As a minor footnote it is a good idea to have a naming convention for (private) member variables, so you will know what variables are local and which are member. I used _data for _ptr
You had a number of places (2 if I remember correctly) where you had off-by-one boundary checks (think pos > capacity instead of >=).
Separation Of Concerns. dynamicDataHolder<T> is a data holder, not an interactiveUserInterviewAboutErrorConditions<T> or databaseUpdateUserInterface<T>. So, don't do UI in the class. Change void insertAtNthPos() to void setData(size_t pos, T value).
Again, naming is important. Don't promise to insert if really you don't unless it's beyond current size bounds. "Insert 7 at pos 1 in {1,2,3}" should result in "{1,7,2,3}", not "{1,7,3}". The name setData
does what is expected and
separates UI concerns and
nicely mirrors getData(size_t pos)
Oh, use consistent index types (size_t in my version) so that you avoid funny looking checks (pos > 0?) and bugs due to mixed signed/unsigned comparisons.
Yes, you had them. No you wouldn't have caught them because you didn't have compiler warnings enabled. Let this reinforce the mantra: "Use The Force Diagnostics"
Don't do "using namespace" at global scope. Or not at all (Why is "using namespace std;" considered bad practice?)
DRY. DRY. DRY. (Don't Repeat Yourself). Sooo many examples of this. You had at least 3 copy-element-data loops. You had several places that resize the allocated array. You had funny stuff like:
void insert(t data) {
int pos;
if (elements >= size) {
int updatedSize = (2 * size);
t* tempPtr = ptr;
ptr = new t[updatedSize];
for (int i = 0; i < size; ++i) {
ptr[i] = tempPtr[i];
}
delete[] tempPtr;
tempPtr = NULL;
size = updatedSize;
pos = elements;
ptr[pos] = data;
incrementElement();
}
else {
if (elements == 0) {
pos = 0;
ptr[pos] = data;
incrementElement();
}
else {
pos = elements;
ptr[pos] = data;
incrementElement();
}
}
It should be obvious that this does the exact same thing three times. The if (elements == 0) check is completely useless, because if you don't have the check, the else branch does the same anyways. For comparison, the new insert looks like:
void insert(T data) { setData(_size, data); }
Oh oops, that got completely zapped, because really, there is nothing special about inserting. But setData is also only ~4 lines of code.
when you add items you have to be careful: you had a very helpful "capacity check". And if the capacity was not enough you doubled capacity. HOWEVER. Who said that was enough? You need to either keep doubling until space is adequate:
void setData(size_t pos, T value) {
while (pos >= _capacity) {
grow();
}
_size = std::max(_size, pos + 1);
_data[pos] = value;
}
or reserve sufficient size at once:
size_t required = _capacity;
while (pos >= required)
required *= 2;
reserve(required);
Const-Correctness: all the observers should be marked const so the compiler knows what it can optimize and the user has guarantees what will never change:
size_t size() const { return _size; }
size_t capacity() const { return _capacity; }
size_t available() const { return _capacity - _size; }
bool compare(const DynArray<T>& obj) const;
The repeated copy/initialization loops can be fixed by using the copy constructor. In related context, make the constructor use a base/member initializer list:
explicit DynArray(size_t initialCapacity = 5)
: _capacity(initialCapacity),
_data(initialCapacity != 0u ? new T[_capacity]{} : nullptr) {}
Now the copy constructor can be:
DynArray(DynArray const& obj) : DynArray(obj.capacity()) {
_size = obj.size();
for (size_t i = 0; i < capacity(); ++i)
_data[i] = obj._data[i];
}
That's the last time you will ever see a copy loop. Why? Observe:
How would you reserve more / less space and without manually copying items? Wouldn't you need a dynamic array class of some kind?
Oh wait. You're implementing it! Don't forget the code you already have:
void reserve(size_t updatedSize) {
DynArray tmp(updatedSize);
for (size_t i = 0; i < std::min(capacity(), tmp.capacity()); ++i) {
tmp._data[i] = _data[i];
}
*this = std::move(tmp);
}
void grow() { reserve(2 * _capacity); }
Now the real magic is in the move constructor/assignment operations.
Copy-and-Swap idiom to the rescue. Turns out you can implement these operations really efficiently and generally with little code:
DynArray(DynArray&& obj) : DynArray(0) { swap(obj); }
DynArray& operator=(DynArray rhs) {
swap(rhs);
return *this;
}
See. Simplicity is a driver. The key is that you just swap with a temporary. The temporary gets destructed, as you want. The swap is pretty simple in its own right:
void swap(DynArray& rhs) {
assert(rhs._data);
std::swap(_capacity, rhs._capacity);
std::swap(_size, rhs._size);
std::swap(_data, rhs._data);
}
There's a lot more thinking behind Copy-And-Swap, but you can find that on your own if you really want: What is the copy-and-swap idiom?
compare checked capacities. I'd say that from a logical standpoint that shouldn't matter.
DynArray<int> a(20), b(12);
for (int v : {1,2,3}) { a.insert(v); b.insert(v); }
assert(a == b); // should pass
it also had bugs, a spurious
result = false;
and erroneous
if (ptr[i] == obj.ptr[i])
{
result = true;
}
That made no sense. If a single item matches, doesn't mean all the previous mismatches are gone.
The above has removed a lot of code, and many many lurking bugs or maintenance head-aches. I reworded your test code to be ... readable. The gotos are obviously gone, the main is now "sane":
int main() {
std::cout << "What do you want to do?\n"
<< "\t1. Run Test Sequence\n"
<< "\t0. Exit Program\n";
for (int userChoice = 0; std::cin >> userChoice;) {
switch (userChoice) {
case 1: testSequence(); break;
case 0: return 0;
default: std::cout << "\nInvalid selection - please try again.\n";
}
}
}
And the information displayed is more complete and much less error prone. Naming can still be improved (obj2? obj4?!??) but I had no semantic information to go by, so I left that as an exorcism for the reader, and also so that you will have an easy time cross-referencing your own test sequence code with mine.
Live Demo
Live On Coliru
#include <iostream>
#include <stdexcept>
#include <cassert>
template <class T> class DynArray {
size_t _capacity = 0;
size_t _size = 0;
T* _data = nullptr;
public:
explicit DynArray(size_t initialCapacity = 5)
: _capacity(initialCapacity),
_data(initialCapacity != 0u ? new T[_capacity]{} : nullptr) {}
DynArray(DynArray const& obj) : DynArray(obj.capacity()) {
_size = obj.size();
for (size_t i = 0; i < capacity(); ++i)
_data[i] = obj._data[i];
}
~DynArray() { delete[] _data; }
void swap(DynArray& rhs) {
assert(rhs._data);
std::swap(_capacity, rhs._capacity);
std::swap(_size, rhs._size);
std::swap(_data, rhs._data);
}
DynArray(DynArray&& obj) : DynArray(0) { swap(obj); }
DynArray& operator=(DynArray rhs) {
swap(rhs);
return *this;
}
T getData(size_t pos) const {
if (pos >= _size) {
throw std::out_of_range("pos");
}
return _data[pos];
}
void setData(size_t pos, T value) {
while (pos >= _capacity)
grow();
_size = std::max(_size, pos+1);
_data[pos] = value;
}
void insert(T data) { setData(_size, data); }
size_t size() const { return _size; }
size_t capacity() const { return _capacity; }
size_t available() const { return _capacity - _size; }
bool compare(const DynArray& obj) const {
if (obj._size != _size) {
return false;
}
for (size_t i = 0; i < _size; i++) {
if (_data[i] != obj._data[i])
return false;
}
return true;
}
void reserve(size_t updatedSize) {
DynArray tmp(updatedSize);
for (size_t i = 0; i < std::min(capacity(), tmp.capacity()); ++i) {
tmp._data[i] = _data[i];
}
*this = std::move(tmp);
}
void grow() { reserve(2 * _capacity); }
};
template <typename T>
void dump(std::string caption, DynArray<T> const& da) {
std::cout << caption << " Capacity: " << da.capacity() << ","
<< " Size: " << da.size() << ","
<< " Available: " << da.available() << ","
<< " Data: {";
for (size_t i = 0; i < da.size(); i++)
std::cout << " " << static_cast<int>(da.getData(i));
std::cout << " }\n";
}
void testSequence() {
{
DynArray<int> obj;
for (size_t i = 0; i < 5; i++) {
obj.insert(i * 2);
}
dump("obj", obj);
if (15 < obj.capacity()) {
std::cout << "\nWarning! Entered size is less than the current size.\n"
<< "Loss of data may occur. Continue? (Y/N)\n";
for (char userChoice; std::cin >> userChoice;) {
if (userChoice == 'y' || userChoice == 'Y') {
obj.reserve(15);
break;
}
if (userChoice == 'n' || userChoice == 'N') {
break;
}
std::cout << "\nInvalid selection - please try again.\n";
}
}
DynArray<int> obj4;
obj4 = obj;
dump("obj4", obj);
}
DynArray<char> obj2(5);
DynArray<char> obj3 = obj2;
dump("obj2", obj2);
dump("obj3", obj3);
std::cout << "obj2 == obj3: " << std::boolalpha << obj3.compare(obj2) << "\n";
try {
std::cout << "obj2.getData(4): " << obj2.getData(4) << std::endl;
} catch(std::out_of_range const& e) {
std::cout << "out of range: " << e.what() << std::endl;
}
while (true) {
std::cout << "\nEnter the details below to insert obj2 values:-\n";
std::cout << "\nPosition: ";
long pos = 0;
if (std::cin >> pos) {
if (pos < 0)
break;
std::cout << "Value: ";
int value = 0;
if (std::cin >> value) {
obj2.setData(pos, value);
}
}
if (!std::cin.eof())
std::cin.clear();
else
break;
dump("obj2", obj2);
}
}
int main() {
do {
std::cout << "What do you want to do?\n"
<< "\t1. Run Test Sequence\n"
<< "\t0. Exit Program\n";
if (int userChoice = 0; std::cin >> userChoice) {
switch (userChoice) {
case 1: testSequence(); continue;
case 0: std::cout << "Goodbye\n"; return 0;
default: std::cout << "\nInvalid selection - please try again.\n";
}
}
if (!std::cin.eof())
std::cin.clear();
} while (std::cin.good());
}
When run with e.g.
g++ -std=c++17 -O2 -Wall -Wextra -pedantic -pthread -fsanitize=address,undefined main.cpp -o sotest
./sotest <<< "1 30 99 3 42 0 -1 0 8 -1 1 -1 0"
You will see the following output:
What do you want to do?
1. Run Test Sequence
0. Exit Program
obj Capacity: 5, Size: 5, Available: 0, Data: { 0 2 4 6 8 }
obj4 Capacity: 5, Size: 5, Available: 0, Data: { 0 2 4 6 8 }
obj2 Capacity: 5, Size: 0, Available: 5, Data: { }
obj3 Capacity: 5,
Size: 0, Available: 5, Data: { } obj2 == obj3: true
obj2.getData(4): out of range: pos
Enter the details below to insert obj2 values:-
Position: Value: obj2 Capacity: 40, Size: 31, Available: 9, Data: { 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 }
Enter the details below to insert obj2 values:-
Position: Value: obj2 Capacity: 40, Size: 31, Available: 9, Data: { 0
0 0 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 }
Enter the details below to insert obj2 values:-
Position: Value: obj2 Capacity: 40, Size: 31, Available: 9, Data: { -1
0 0 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 }
Enter the details below to insert obj2 values:-
Position: Value: obj2 Capacity: 40, Size: 31, Available: 9, Data: { 8
0 0 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 }
Enter the details below to insert obj2 values:-
Position: What do you want to do?
1. Run Test Sequence
0. Exit Program
obj Capacity: 5, Size: 5, Available: 0, Data: { 0 2 4 6 8 }
obj4 Capacity: 5, Size: 5, Available: 0, Data: { 0 2 4 6 8 }
obj2 Capacity: 5, Size: 0, Available: 5, Data: { }
obj3 Capacity: 5,
Size: 0, Available: 5, Data: { }
obj2 == obj3: true
obj2.getData(4): out of range: pos
Enter the details below to insert obj2 values:-
Position: What do you want to do?
1. Run Test Sequence
0. Exit Program
Goodbye

Priority Queue using heap, values with same key don't follow FIFO (first in first out)

So I'm trying to create this priority queue to handle my "Order" objects, I'm running into a problem where an object containing the same key/priority will be placed at an early earlier position than others initialized first. I have provided the expected and received output alongside the 83 lines of code of how I constructed my heap with notes
#include <iostream>
#include <vector>
struct Order {
int value = -1;
int priority = -1;
bool operator <(Order const& RHS) { return priority < RHS.priority; }
};
class heap {
private:
std::vector<Order> orders{ Order{} };
int size{}; //initalizes it at 0
int p(int index) { return index >> 1; }
int l(int index) { return index << 1; }
int r(int index) { return (index << 1) + 1; }
public:
bool isEmpty() const { return size == 0; }
void shiftUp(int position);
void shiftDown(int position);
void add(Order new_entry);
Order removeTop();
Order& getTop() { return orders[1]; }
};
template <typename T>
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
heap h;
h.add(Order{1,3}); h.add(Order{2,2});
h.add(Order{3,3}); h.add(Order{5,1});
h.add(Order{6,2}); h.add(Order{7,2});
h.add(Order{8,3}); h.add(Order{9,1});
h.add(Order{23,3});
std::cout << "value" << " key(priority)" << "\n";
for (int i = 0; i < 8; i++) {
Order temp = h.removeTop();
std::cout << temp.value << "\t " << temp.priority << "\n";
}
}
void heap::shiftUp(int position) {
if (position > size) return;
if (position == 1) return;
if (orders[p(position)] < orders[position]) {
mySwap(orders[position], orders[p(position)]);
shiftUp(p(position));
}
}
void heap::shiftDown(int position) {
if (position > size) return;
int greaterPosition = position;
if (l(position) <= size && orders[position] < orders[l(position)])
greaterPosition = l(position);
if (r(position) <= size && orders[greaterPosition] < orders[r(position)])
greaterPosition = r(position);
if (greaterPosition != position) {
mySwap(orders[position], orders[greaterPosition]);
shiftDown(greaterPosition);
}
}
void heap::add(Order new_entry) {
if (size + 1 >= orders.size()) orders.push_back(Order{});
orders[++size] = new_entry;
shiftUp(size);
}
Order heap::removeTop() {
Order temp = orders[1];
mySwap(orders[1],orders[orders.size() - 1]); size--;
orders.pop_back();
shiftDown(1);
return temp;
}
/*
Expected Output
Value key(priority)
1 3
3 3
8 3
23 3
2 2
6 2
7 2
5 1
9 1
Recieved/wrong Output
value key(priority)
1 3
23 3
3 3
8 3
2 2
6 2
7 2
5 1
*/
Fixed code from answered information above
#include <iostream>
#include <vector>
struct Order {
int value = -1;
int priority = -1;
int FIFO;
bool operator <(Order const& RHS) {
if (priority == RHS.priority)
return FIFO > RHS.FIFO;
else
return priority < RHS.priority;
} //compares keys for larger presidence
};
class heap {
private:
std::vector<Order> orders{ Order{} };
int size{}; //initalizes it at 0
int p(int index) { return index >> 1; }
int l(int index) { return index << 1; }
int r(int index) { return (index << 1) + 1; }
public:
bool isEmpty() const { return size == 0; }
void shiftUp(int position);
void shiftDown(int position);
void add(Order new_entry);
Order removeTop();
Order& getTop() { return orders[1]; }
};
template <typename T>
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
heap h;
h.add(Order{1,3}); h.add(Order{2,2});
h.add(Order{3,3}); h.add(Order{5,1});
h.add(Order{6,2}); h.add(Order{7,2});
h.add(Order{8,3}); h.add(Order{9,1});
h.add(Order{23,3});
std::cout << "value" << " key(priority)" << "\n";
for (int i = 0; i < 8; i++) {
Order temp = h.removeTop();
std::cout << temp.value << "\t " << temp.priority << "\n";
}
}
void heap::shiftUp(int position) {
if (position > size) return;
if (position == 1) return;
if (orders[p(position)] < orders[position]) {
mySwap(orders[position], orders[p(position)]);
shiftUp(p(position));
}
}
void heap::shiftDown(int position) {
if (position > size) return;
int greaterPosition = position;
if (l(position) <= size && orders[position] < orders[l(position)])
greaterPosition = l(position);
if (r(position) <= size && orders[greaterPosition] < orders[r(position)])
greaterPosition = r(position);
if (greaterPosition != position) {
mySwap(orders[position], orders[greaterPosition]);
shiftDown(greaterPosition);
}
}
void heap::add(Order new_entry) {
if (size + 1 >= orders.size()) orders.push_back(Order{});
new_entry.FIFO = size + 1;
orders[++size] = new_entry;
shiftUp(size);
}
Order heap::removeTop() {
Order temp = orders[1];
mySwap(orders[1],orders[orders.size() - 1]); size--;
orders.pop_back();
shiftDown(1);
return temp;
}
In general, heap does not have FIFO property until you implement something that helps doing so. In your order class, you are only comparing using the priority value. In your Order class, you are comparing two Orders by only their priority value. You need a additional variable that serves as the purpose for recording the timing when that value was inserted, and compare according to that.
If you are using the variable value for that purpose, you need to specify in your overloaded < method, what do you want to do when two Order's priority values are equal. Currently, you are only using the priority variable to compare. You are not specifying what do you want to do when the priority of two Orders are equal. You have to specify what do you want to do when the priority value of two variables are equal. Maybe compare a timing variable.

While Overloading The << Operator Was It Correctly Formatted?

I have been getting outputs and sometimes even getting the complete output, however I don't quite understand why I'd be getting said outputs. I want to believe it has something to do with my overloading of said operator "<<" when I perform the operation of outputting the information in the "OpenSea" object. Any leads would be tremendously helpful and thank you for your time!
Note: I included only the necessary files but will update if you think you need more to understand the full scope of my situation. Also there is no need to give me tips on how to format my code as I know a lot of it can be reworked for optimization.
main.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
#include "aquaSea.h"
using namespace std;
int main ()
{
srand (time (NULL));
// Simulation
Sea OpenSea (17, 17);
cout << OpenSea;
}
aquaClasses.h <-- "main" header file
#ifndef AQUACLASSES_H
#define AQUACLASSES_H
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <iomanip>
// Constants
const short int AMT_FISH = 200;
const short int AMT_KWHALES = 2;
const short int AMT_PENGS = 50;
const short int MAX_SIM_INTERATIONS = 10000;
const short int MAX_SEA_GRID = 25;
const short int MAX_SEA_SIZE = 625;
// Functions
template <typename TYPE> int calculate_distance (int obj1_x, int obj1_y,
TYPE obj2);
template <typename TYPE> int calculate_direction (int obj1_x, int obj1_y,
TYPE obj2);
#endif
aquaSea.h
#ifndef AQUASEA_H
#define AQUASEA_H
// Forward Declarations to circumvent circular dependency
class Fish;
class Penguin;
class Killer_Whale;
class Sea
{
private:
char m_grid [MAX_SEA_GRID][MAX_SEA_GRID];
int m_fish;
int m_kwhales;
int m_pengs;
int m_size;
int m_height;
int m_width;
void clear ();
void populate ();
public:
Sea (const int grid_size_height, const int grid_size_width);
friend std::ostream &operator<<(std::ostream &os, Sea obj);
int getHeight () const {return m_height;};
int getWidth () const {return m_width;};
void setCell (int obj_x, int obj_y, char cell_symbol);
// Appropriate accessor/mutator functions
};
#endif
aquaSea.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaPenguin.h"
#include "aquaKillerWhale.h"
#include "aquaSea.h"
using namespace std;
// - [row][column]
Sea::Sea (const int grid_size_height, const int grid_size_width)
{
m_fish = 200;
m_kwhales = 2;
m_pengs = 50;
if ((grid_size_height || grid_size_width) <= 0)
{
if (grid_size_height <= 0 && grid_size_width > 0)
{
m_size = MAX_SEA_GRID * grid_size_width;
m_width = grid_size_width;
m_height = MAX_SEA_GRID;
}
else if (grid_size_width <= 0 && grid_size_height > 0)
{
m_size = MAX_SEA_GRID * grid_size_height;
m_width = MAX_SEA_GRID;
m_height = grid_size_height;
}
else if (grid_size_height <= 0 && grid_size_width <= 0)
{
m_size = MAX_SEA_GRID * MAX_SEA_GRID;
m_height = MAX_SEA_GRID;
m_width = MAX_SEA_GRID;
}
}
else
{
m_size = grid_size_height * grid_size_width;
m_height = grid_size_height;
m_width = grid_size_width;
}
clear ();
populate ();
}
ostream &operator<<(ostream &os, Sea obj)
{
os << "Sea Height: " << obj.m_width << endl << "Sea Wdith: "
<< obj.m_width << endl << "Sea Size: " << obj.m_size
<< endl;
os << "Grid View: " << endl;
for (int i = 0; i < obj.m_height; i++)
{
for (int j = 0; j < obj.m_width; j++)
{
os << obj.m_grid [i][j];
}
os << endl;
}
return os;
}
void Sea::clear ()
{
for (int i = 0; i < m_height; i++)
{
for (int j = 0; j < m_width; j++)
{
m_grid[i][j] = 'O';
}
}
return;
}
void Sea::populate ()
{
// Special simluation variables
bool applyFish = true;
bool applyKWhales = false;
bool applyPengs = false;
int amtFishPop = 35;
int amtKWhalesPop = 2;
int amtPengPop = 20;
int index = 0;
int randGridRow = 0;
int randGridCol = 0;
int totalPop = amtFishPop + amtKWhalesPop + amtPengPop;
Fish arr_fish [AMT_FISH];
Killer_Whale arr_kwhales [AMT_KWHALES];
Penguin arr_pengs [AMT_PENGS];
for (int i = 0; i < totalPop; i++)
{
// Grab random place on grid to apply and check if grid plot is open
randGridRow = rand () % 16;
randGridCol = rand () % 16;
while (m_grid [randGridRow][randGridCol] != 'O')
{
randGridRow = rand () % 16;
randGridCol = rand () % 16;
}
// Populate and Update Fish
if (amtFishPop > 0 && applyFish == true)
{
arr_fish[index].setX (randGridCol);
arr_fish[index].setY (randGridRow);
setCell (arr_fish[index].getX (), arr_fish[index].getY (), 'F');
amtFishPop--;
index++;
}
else if (amtFishPop == 0)
{
applyFish = false;
applyKWhales = true;
index = 0;
}
// Populate and Update Killer Whales
if (amtKWhalesPop > 0 && applyKWhales == true)
{
arr_kwhales[index].setX (randGridCol);
arr_kwhales[index].setY (randGridRow);
setCell (arr_kwhales[index].getX (), arr_kwhales[index].getY (), 'K');
amtKWhalesPop--;
index++;
}
else if (amtKWhalesPop == 0)
{
applyKWhales = false;
applyPengs = true;
index = 0;
}
// Populate and Update Penguins
if (amtPengPop > 0 && applyPengs == true)
{
arr_pengs[index].setX (randGridCol);
arr_pengs[index].setY (randGridRow);
setCell (arr_pengs[index].getX (), arr_pengs[index].getY (), 'P');
amtPengPop--;
index++;
}
else if (amtPengPop == 0)
{
applyPengs = false;
index = 0;
}
}
return;
}
void Sea::setCell (int obj_x, int obj_y, char cell_symbol)
{
m_grid [obj_x][obj_y] = cell_symbol;
return;
}
Types of Output
Wanted:
- Image
Unwanted:
- Image
STOP! AFTER THIS POINT IS OPTIONAL CODE TO FURTHER UNDERSTAND THE SITUATION
Other Code Of Reference If You Want But I Don't Think It's Needed
aquaFish.h
#ifndef AQUAFISH_H
#define AQUAFISH_H
class Fish
{
private:
int m_fish_amt_food;
int m_fish_x;
int m_fish_y;
bool m_fish_alive;
public:
Fish ();
int getX () const {return m_fish_x;};
int getY () const {return m_fish_y;};
void setX (int new_x) {m_fish_x = new_x;};
void setY (int new_y) {m_fish_y = new_y;};
int getFishAmtFood () const {return m_fish_amt_food;};
void move ();
};
#endif
aquaFish.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
using namespace std;
Fish::Fish ()
{
int randNum = rand () % 10 + 1;
m_fish_amt_food = randNum;
m_fish_x = -1;
m_fish_y = -1;
}
void Fish::move ()
{
int randDir = rand () % 8 + 1;
if (randDir == 1)
{
m_fish_y++;
}
else if (randDir == 2)
{
m_fish_x++;
m_fish_y++;
}
else if (randDir == 3)
{
m_fish_x++;
}
else if (randDir == 4)
{
m_fish_x++;
m_fish_y--;
}
else if (randDir == 5)
{
m_fish_y--;
}
else if (randDir == 6)
{
m_fish_x--;
m_fish_y--;
}
else if (randDir == 7)
{
m_fish_x--;
}
else if (randDir == 8)
{
m_fish_x--;
m_fish_y++;
}
return;
}
aquaPenguin.h
#ifndef AQUAPENGUIN_H
#define AQUAPENGUIN_H
// Forward Declarations to circumvent circular dependancy
class Sea;
class Fish;
class Killer_Whale;
class Penguin
{
private:
int m_peng_health; // 0-100
int m_peng_x;
int m_peng_y;
bool m_peng_alive;
public:
Penguin ();
int getX () const {return m_peng_x;};
int getY () const {return m_peng_y;};
void setX (int new_x) {m_peng_x = new_x;};
void setY (int new_y) {m_peng_y = new_y;};
void move (Sea obj_sea, Fish arr_fish [], int arr_fish_size,
Killer_Whale arr_kwhale [], int arr_kwhale_size);
};
#endif
aquaPenguin.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
#include "aquaSea.h"
#include "aquaFunctions.cpp"
using namespace std;
Penguin::Penguin ()
{
m_peng_health = rand () % (81 - 60) + 60;
m_peng_x = -1;
m_peng_y = -1;
m_peng_alive = false;
}
void Penguin::move (Sea obj_sea, Fish arr_fish [], int arr_fish_size,
Killer_Whale arr_kwhale [], int arr_kwhale_size)
{
int actuDistToFish = 8;
int currDistToFish = 0;
int tempMoveX = 0;
int tempMoveY = 0;
int amtMove = 0;
int direction = 0;
int fishIndex = 0;
bool moveAwayKillerWhale = false;
bool fishInRange = false;
// Determine amount of cells to move in sea
if (m_peng_health >= 81 && m_peng_health <= 100)
{
amtMove = 5;
}
else if (m_peng_health >= 61 && m_peng_health <= 80)
{
amtMove = 4;
}
else if (m_peng_health >= 41 && m_peng_health <= 60)
{
amtMove = 3;
}
else if (m_peng_health >= 21 && m_peng_health <= 40)
{
amtMove = 2;
}
else if (m_peng_health >= 1 && m_peng_health <= 20)
{
amtMove = 1;
}
else
{
cout << "Chicken of the sea at: " << m_peng_x << " " << m_peng_y
<< endl;
return;
}
// ADD: Find if any killer whales are near first and if so then penguin just moves away
// Find if any fish are near <-- THIS IS WRONG, YOU NEED TO FIND THE CLOSEST FISH
for (int i = 0; i < arr_fish_size; i++)
{
currDistToFish = calculate_distance (m_peng_x, m_peng_y,
arr_fish[i]);
if (currDistToFish <= 8)
{
if (currDistToFish < actuDistToFish)
{
actuDistToFish = currDistToFish;
fishIndex = i;
fishInRange = true;
}
}
}
// ADD: If fish and whale are found do something, we decide. Otherwise move randomly Peng See Dist 8.0
// ADD Move 1 tick then gauge situation again
for (int k = 0; k < amtMove; k++)
{
if (fishInRange == true && moveAwayKillerWhale == false)
{
tempMoveX = m_peng_x; // temp used for storing before changing
tempMoveY = m_peng_y; // temp used for storing before changing
direction = calculate_direction (m_peng_x, m_peng_y,
arr_fish[fishIndex]);
cout << "Penguin pos before moving: " << m_peng_x << ","
<< m_peng_y << endl;
cout << "Closest Fish pos: " << arr_fish[fishIndex].getX () << ","
<< arr_fish[fishIndex].getY () << endl;
if (m_peng_health == 0)
{
cout << "Chicken of the sea at: " << m_peng_x << " " << m_peng_y
<< endl;
return;
}
if (direction == 1)
{
actuDistToFish--;
m_peng_health--;
tempMoveY++;
}
else if (direction == 2)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
tempMoveY++;
}
else if (direction == 3)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
}
else if (direction == 4)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
tempMoveY--;
}
else if (direction == 5)
{
actuDistToFish--;
m_peng_health--;
tempMoveY--;
}
else if (direction == 6)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
tempMoveY--;
}
else if (direction == 7)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
}
else if (direction == 8)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
tempMoveY++;
}
else
{
cout << "[ERROR]: Penguin direction messed up." << endl;
}
// MODIFY: Lastly check if out of bounds and then move peng
if (tempMoveX > obj_sea.getWidth ()
|| tempMoveX < -(obj_sea.getWidth ()))
{
m_peng_x = m_peng_x; // AKA dont move
m_peng_y = m_peng_y;
}
else if (tempMoveY > obj_sea.getHeight ()
|| tempMoveY < -(obj_sea.getHeight ()))
{
m_peng_x = m_peng_x; // AKA dont move
m_peng_y = m_peng_y;
}
else
{
obj_sea.setCell (m_peng_x, m_peng_y, 'O'); // Delete old cell
m_peng_x = tempMoveX;
m_peng_y = tempMoveY;
obj_sea.setCell (m_peng_x, m_peng_y, 'P'); // Set new cell
}
// Check if peng eats after moving
if (actuDistToFish == 0)
{
// Stop moving
amtMove = 0;
// Eat fish
m_peng_health += arr_fish[fishIndex].getFishAmtFood ();
// ADD: Remove fish from grid
}
cout << "Penguin pos after moving: " << m_peng_x << ","
<< m_peng_y << endl;
}
else if (fishInRange == false && moveAwayKillerWhale == true)
{
}
else if (fishInRange == false && moveAwayKillerWhale == false)
{
// If no fish, movement is random, else it's towards fish how ever many
// step the penguin can go
direction = rand () % 8 + 1;
if (direction == 1)
{
m_peng_y++;
}
else if (direction == 2)
{
m_peng_x++;
m_peng_y++;
}
else if (direction == 3)
{
m_peng_x++;
}
else if (direction == 4)
{
m_peng_x++;
m_peng_y--;
}
else if (direction == 5)
{
m_peng_y--;
}
else if (direction == 6)
{
m_peng_x--;
m_peng_y--;
}
else if (direction == 7)
{
m_peng_x--;
}
else if (direction == 8)
{
m_peng_x--;
m_peng_y++;
}
else
{
cout << "[ERROR]: Penguin random direction messed up." << endl;
}
}
}
return;
}
aquaKillerWhale.h
#ifndef AQUAKILLERWHALE_H
#define AQUAKILLERWHALE_H
class Penguin;
class Killer_Whale
{
private:
int m_kwhale_amt_pengs;
int m_kwhale_x;
int m_kwhale_y;
public:
Killer_Whale ();
int getX () const {return m_kwhale_x;};
int getY () const {return m_kwhale_y;};
void setX (int new_x) {m_kwhale_x = new_x;};
void setY (int new_y) {m_kwhale_y = new_y;};
void move (Penguin arr_peng []);
};
#endif
aquaKillerWhale.cpp
#include "aquaClasses.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
using namespace std;
Killer_Whale::Killer_Whale ()
{
m_kwhale_x = -1;
m_kwhale_y = -1;
}
void Killer_Whale::move (Penguin arr_peng [])
{
return;
}
aquaFunctions.cpp
#include "aquaClasses.h"
using namespace std;
// Functions
template <typename TYPE>
int calculate_direction (int obj1_x, int obj1_y, TYPE obj2)
{
int calculatedX = obj2.getX () - obj1_x;
int calculatedY = obj2.getY () - obj1_y;
int direction = 0;
if (calculatedX == 0 && calculatedY > 0)
{
direction = 1;
}
else if (calculatedX > 0 && calculatedY > 0)
{
direction = 2;
}
else if (calculatedX > 0 && calculatedY == 0)
{
direction = 3;
}
else if (calculatedX > 0 && calculatedY < 0)
{
direction = 4;
}
else if (calculatedX == 0 && calculatedY < 0)
{
direction = 5;
}
else if (calculatedX < 0 && calculatedY < 0)
{
direction = 6;
}
else if (calculatedX < 0 && calculatedY == 0)
{
direction = 7;
}
else if (calculatedX < 0 && calculatedY > 0)
{
direction = 8;
}
else
{
cout << "[ERROR]: Direction calculation failed." << endl;
}
return direction;
}
template <typename TYPE>
int calculate_distance (int obj1_x, int obj1_y, TYPE obj2)
{
int distance = sqrt ((obj1_x - obj2.getX ())
* (obj1_x - obj2.getX ())
+ (obj1_y - obj2.getY ())
* (obj1_y - obj2.getY ()));
return distance;
}

Writing a priority queue with a max heap structure in c++

I am writing a priority queue with a max heap structure as an assignment for school. I can either write it as an array or I can use a vector. I chose a vector. So the assignment is this, the user chooses options from a menu where he either wants to add,print, or view the elements. When the user chooses to add he gets ask who wants to be added, the instructor, student, or TA. He can enter i,I,t,T,S,s. The instructor having the highest priority where if the user chooses the option to print and there is an instructor in the queue he gets to go first. The TA having the second highest priority where if there is a TA and a student in the queue, the TA goes first. If there is is more than one instructor than the queue acts as a normal queue. I have written most of it, or tried. I got my max heap implementation from my textbook since they provide one. Now the problem is this, when I have more than one item in the priority queue and I choose to print, it crashes and gives me a vector subscript out of range exception. I been trying to fix it and no luck. Also, when I try to print the elements in the queue or print them, it needs to say the job# with the name of the person. Can someone help me find a way to implement that.
#pragma once
#include <vector>
struct Heap
{
std::vector<int> m_elements;
void ReHeapDown(int, int);
void ReHeapUp(int, int);
void Swap(int& a, int& b);
};
#include "heap.h"
void Heap::ReHeapDown(int index, int bottom)
{
int maxChild, rightChild, leftChild;
leftChild = index * 2 + 1;
rightChild = index * 2 + 2;
if (leftChild <= bottom)
{
if (leftChild == bottom)
maxChild = leftChild;
else
{
if (m_elements[leftChild] <= m_elements[rightChild])
maxChild = rightChild;
else
maxChild = leftChild;
}
if (m_elements[index] < m_elements[maxChild])
{
Swap(m_elements[index], m_elements[maxChild]);
ReHeapDown(maxChild, bottom);
}
}
}
void Heap::ReHeapUp(int index, int bottom)
{
int parent;
if (bottom > index)
{
parent = (bottom - 1) / 2;
if (m_elements[parent] < m_elements[bottom])
{
Swap(m_elements[parent], m_elements[bottom]);
ReHeapUp(index, parent);
}
}
}
void Heap::Swap(int& a, int& b)
{
int temp;
temp = a;
a = b;
b = temp;
}
#include <iostream>
#include "heap.h"
#pragma once
class PQTYPE
{
private:
Heap m_Items;
public:
bool isEmpty() const;
void Enqueue(int, std::string);
void Dequeue(int, std::string);
void printElements();
};
#include "pqtype.h"
bool PQTYPE::isEmpty() const
{
return m_Items.m_elements.empty();
}
void PQTYPE::Enqueue(int newItem, std::string lName)
{
if (lName == "Student")
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (lName == "TA")
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (lName == "Instructor")
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
}
void PQTYPE::Dequeue(int item, std::string lName)
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
m_Items.m_elements[0] = m_Items.m_elements.back();
std::cout << "Now printing Job#" << m_Items.m_elements[item - 1] << " " << lName.c_str() << std::endl;
m_Items.m_elements.pop_back();
m_Items.ReHeapDown(0, item - 1);
}
}
void PQTYPE::printElements()
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
for (int i = 0; i < m_Items.m_elements.size(); i++)
{
std::cout << "Job#" << m_Items.m_elements[i] << std::endl;
}
}
}
#include"pqtype.h"
struct Person
{
int m_priority;
std::string m_name;
Person()
{
m_priority = 0;
m_name = " ";
}
};
int showMenu();
void addJobs(PQTYPE&, Person&);
void printJobs(PQTYPE&, Person&);
void viewJobs(PQTYPE&);
int main()
{
int option;
Person p;
PQTYPE pq;
do
{
option = showMenu();
switch (option)
{
case 1: addJobs(pq, p);
break;
case 2: printJobs(pq, p);
break;
case 3: viewJobs(pq);
break;
case 4:
break;
default: std::cout << "Wrong input\n";
break;
}
} while (option != 4);
return 0;
}
int showMenu()
{
int choice;
std::cout << " 1.)Add Job\n";
std::cout << " 2.)Print Job\n";
std::cout << " 3.)View Jobs\n";
std::cout << " 4.)Exit\n";
std::cout << " Enter Choice: ";
std::cin >> choice;
return choice;
}
void addJobs(PQTYPE& pq, Person& per)
{
char jobChoice;
std::cout << "Who is the job for ( Instructor(i or I), TA(t or T), Student(s or S) :";
std::cin >> jobChoice;
if (jobChoice == 'S' || jobChoice == 's')
{
per.m_priority++;
per.m_name = "Student";
pq.Enqueue(per.m_priority, per.m_name);
}
else if (jobChoice == 'T' || jobChoice == 't')
{
per.m_priority++;
per.m_name = "TA";
pq.Enqueue(per.m_priority, per.m_name);
}
if (jobChoice == 'I' || jobChoice == 'i')
{
per.m_priority++;
per.m_name = "Instructor";
pq.Enqueue(per.m_priority, per.m_name);
}
}
void printJobs(PQTYPE& pq, Person& p)
{
pq.Dequeue(p.m_priority, p.m_name);
}
void viewJobs(PQTYPE& pq)
{
pq.printElements();
}
In your original code the index used inside Dequeue() for accessing the vector doesn't seem to be initialised in the right way. Let's assume that you have added two entries to your list. In this case the value of P.m_priority inside your main() is 2. Now you're calling printJobs() for the first time. printJobs() calls pq.Dequeue(p.m_priority, p.m_name), so Dequeue() gets p.m_priority as its parameter item. Keep in mind that item has the value 2.
m_Items.m_elements[0] = m_Items.m_elements.back();
std::cout << "Now printing Job#" << m_Items.m_elements[item - 1] << " " << lName.c_str() << std::endl;
m_Items.m_elements.pop_back();
You're accessing your std::vector using an index of item - 1. This works for the first time, as there are two elements in your list. In this call, there is also a pop_back() done on your list, which decreases its size by one. The next time you call printJobs(), the given parameter item won't have changed, it still has the value 2. When you access your Itemlist, there is no longer an index of 1, and an subscript out of range exception will be thrown.
There were no fixed priorities assigned to the three entry types in your original version, so I added these (see addJobs() ).
So a possible solution to store the person's name could look like this:
struct Person
{
int m_priority;
std::string m_name;
Person()
{
m_priority = 0;
m_name = " ";
}
};
struct Heap
{
std::vector<Person> m_elements;
void ReHeapDown(int, int);
void ReHeapUp(int, int);
void Swap(Person& a, Person& b);
};
void Heap::ReHeapDown(int index, int bottom)
{
int maxChild, rightChild, leftChild;
leftChild = index * 2 + 1;
rightChild = index * 2 + 2;
if (leftChild <= bottom)
{
if (leftChild == bottom)
maxChild = leftChild;
else
{
if (m_elements[leftChild].m_priority <= m_elements[rightChild].m_priority)
maxChild = rightChild;
else
maxChild = leftChild;
}
if (m_elements[index].m_priority < m_elements[maxChild].m_priority)
{
Swap(m_elements[index], m_elements[maxChild]);
ReHeapDown(maxChild, bottom);
}
}
}
void Heap::ReHeapUp(int index, int bottom)
{
int parent;
if (bottom > index)
{
parent = (bottom - 1) / 2;
if (m_elements[parent].m_priority < m_elements[bottom].m_priority)
{
Swap(m_elements[parent], m_elements[bottom]);
ReHeapUp(index, parent);
}
}
}
void Heap::Swap(Person& a, Person& b)
{
Person temp;
temp = a;
a = b;
b = temp;
}
#include <iostream>
class PQTYPE
{
private:
Heap m_Items;
public:
bool isEmpty() const;
void Enqueue(Person);
void Dequeue();
void printElements();
};
bool PQTYPE::isEmpty() const
{
return m_Items.m_elements.empty();
}
void PQTYPE::Enqueue(Person newItem)
{
if (!newItem.m_name.compare("Student"))
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (!newItem.m_name.compare("TA"))
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
else if (!newItem.m_name.compare("Instructor"))
{
m_Items.m_elements.push_back(newItem);
m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
}
}
void PQTYPE::Dequeue()
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
Person front = m_Items.m_elements.front();
std::cout << "Now printing Job#" << front.m_priority << " " << front.m_name.c_str() << std::endl;
m_Items.m_elements.erase(m_Items.m_elements.begin());
m_Items.ReHeapDown(0, m_Items.m_elements.size() - 1);
}
}
void PQTYPE::printElements()
{
if (isEmpty())
std::cout << "No jobs to print\n";
else
{
for (int i = 0; i < m_Items.m_elements.size(); i++)
{
std::cout << "Job#" << m_Items.m_elements[i].m_priority << " " << m_Items.m_elements[i].m_name.c_str() << std::endl;
}
}
}
int showMenu();
void addJobs(PQTYPE&, Person&);
void printJobs(PQTYPE&, Person&);
void viewJobs(PQTYPE&);
int showMenu()
{
int choice;
std::cout << " 1.)Add Job\n";
std::cout << " 2.)Print Job\n";
std::cout << " 3.)View Jobs\n";
std::cout << " 4.)Exit\n";
std::cout << " Enter Choice: ";
std::cin >> choice;
return choice;
}
void addJobs(PQTYPE& pq, Person& per)
{
char jobChoice;
std::cout << "Who is the job for ( Instructor(i or I), TA(t or T), Student(s or S) :";
std::cin >> jobChoice;
if (jobChoice == 'S' || jobChoice == 's')
{
per.m_priority = 0;
per.m_name = "Student";
pq.Enqueue(per);
}
else if (jobChoice == 'T' || jobChoice == 't')
{
per.m_priority = 1;
per.m_name = "TA";
pq.Enqueue(per);
}
if (jobChoice == 'I' || jobChoice == 'i')
{
per.m_priority = 2;
per.m_name = "Instructor";
pq.Enqueue(per);
}
}
void printJobs(PQTYPE& pq)
{
pq.Dequeue();
}
void viewJobs(PQTYPE& pq)
{
pq.printElements();
}
int main()
int option;
Person p;
PQTYPE pq;
do
{
option = showMenu();
switch (option)
{
case 1: addJobs(pq, p);
break;
case 2: printJobs(pq);
break;
case 3: viewJobs(pq);
break;
case 4:
break;
default: std::cout << "Wrong input\n";
break;
}
} while (option != 4);
return 0
}
Are you sure that the methods ReHeapUp and ReHeapDown meet your requirements? And shouldn't there be a distinction between job number and priority?

Overloading Operator most likely not working [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Could you guys check out my function somethingWrong(), and my overloading operators.
Sometimes when I run the function somethingwrong() I get "True" and sometimes "False".
I am not changing anything, why is this happening?
This is a Dijkstra algorithm graph I am working in.
Thank You
main.cpp:
#include <iostream>
#include <fstream>
#include "graph.h"
using namespace std;
int main(){
//
graph g;
g.addVertices();
//g.printAll();
g.addEdges();
cout << "Hello" << endl;
//g.printAdjList(5.74);
//g.DJAlgorithm();
g.somethingWrong();
return 0;
}
graph.h
#include <iostream>
#include <list>
#include <fstream>
#include "minHeap.h"
using namespace std;
class graph{
protected:
class vertex{
public:
int x;
int y;
double cost;
double weight;
vertex * parent;
list<vertex*> adjacencyList;
vertex(int xc, int yc, double c){
x = xc;
y = yc;
cost = c;
weight = -1;
parent = NULL;
}
// operator overloading
// dont know if to add =
vertex & vertex::operator=(vertex * z){
return *z;
}
bool vertex::operator==(vertex * z){
return (this->weight == z->weight);
}
bool vertex::operator!=(vertex * z){
return (this->weight != z->weight);
}
bool vertex::operator<=(vertex * z){
return (this->weight <= z->weight);
}
bool vertex::operator<(vertex * z){
return (this->weight < z->weight);
}
bool vertex::operator>=(vertex * z){
return (this->weight >= z->weight);
}
bool vertex::operator>(vertex * z){
return (this->weight > z->weight);
}
};
list<vertex*> vertexList;
int numOfVertices;
public:
int sX;
int sY;
int eX;
int eY;
graph(){
numOfVertices = 0;
}
void somethingWrong(){
vertex *dog = new vertex(0,0,0);
vertex * cat = new vertex(0,0,0);
dog->weight = 5;
cat->weight = 9;
if(dog < cat){
cout << "True" << endl;
}
else{
cout << "False" << endl;
}
}
void addVertices(){
ifstream inFile;
double w;
int countX = 1;
int countY = 1;
inFile.open("grid.txt");
if(!inFile){
cout << "Error opening file!" << endl;
return;
}
// get the coordinates of the starting and
// ending position
inFile >> sX;
inFile >> sY;
inFile >> eX;
inFile >> eY;
// get the grid of data
while(!inFile.eof()){
inFile >> w;
vertexList.push_back(new vertex(countX,countY,w));
numOfVertices++;
countX++;
if(inFile.peek() == '\n'){
countX = 1;
countY++;
}
}
}
void addEdges(){
for each(vertex * v in vertexList){
for each(vertex * w in vertexList){
if(((v->x == w->x) && (abs(v->y - w->y)) == 1) || ((v->y == w->y) && (abs(v->x - w->x) == 1))){
v->adjacencyList.push_back(w);
}
}
}
}
// prints all the grid, for verification purposes
void printAll(){
cout << sX << " " << sY << endl;
cout << eX << " " << eY << endl;
for each(vertex * v in vertexList){
cout << v->x << " " << v->y << " " << v->cost << endl;
}
}
// print a vertex's adjacency list
void printAdjList(double c){
for each(vertex * v in vertexList){
if(v->cost == c){
for each(vertex * w in v->adjacencyList){
cout << w->x << " " << w->y << " " << w->cost << endl;
}
return;
}
}
}
// problelm here
// prints the path from vertex x
void printPath(vertex * x){
if(x != NULL){
//cout << "sup" << endl;
printPath(x->parent);
cout << "(" << x->x << "," << x->y << ") weight: " << x->weight << endl;
}
}
void DJAlgorithm(){
// min Heap item
minHeap<vertex*> C(numOfVertices);
vertex * s;
vertex * x;
vertex * e;
// find required start and end vertices
for each(vertex * v in vertexList){
if(v->x == sX && v->y == sY){
s = v;
}
if(v->x == eX && v->y == eY){
e = v;
}
}
// set up all values
for each(vertex * v in vertexList){
v->weight = -1;
v->parent = NULL;
}
s->weight = 0;
// insert everything in to the queue/minHeap
for each (vertex * v in vertexList){
C.insert(v);
}
while(!C.empty()){
x = C.extractMin();
for each(vertex * v in x->adjacencyList){
// relax
// if not discovered
if(v->weight == -1){
v->weight = x->weight;
v->parent = x;
}
// if already discovered
else{
if(x->weight + v->cost < v->weight){
v->weight = x->weight + v->cost;
v->parent = x;
}
}
}
}
// print out the path back
printPath(e);
}
};
// min heap data structure
#include <iostream>
using namespace std;
template<class THING>
class minHeap
{
private:
//array to hold items
THING * items;
int n;
//return index of parent of i
int parent(int i)
{
return (i-1)/2;
}
//return index of left child of i
int lchild(int i)
{
return i*2 + 1;
}
//return index of right child of i
int rchild(int i)
{
return i*2 + 2;
}
//return index of smaller child
int minChild(int i)
{
if( lchild(i) >= n ) //a leaf!
return i;
else if( lchild(i) == (n-1) )
return lchild(i);
else if( items[lchild(i)] < items[rchild(i)] )
return lchild(i);
else
return rchild(i);
}
//bubble item at index current up tree
//until there's no more violation
void bubbleUp(int current)
{
// ignoring all these
if( current == 0 ) //the root! easy!
{
//do nothing, done, no violation, base case!
}
else if( items[current] >= items[parent(current)] ) //no violation
{
//do nothing!, done, go home, base case!
}
else
{
//step 1: swap current with parent
swap( items[current], items[parent(current)] );
//step 2: keep bubbling item up
bubbleUp( parent(current) );
}
}
void bubbleDown(int current)
{
if( lchild(current) >= n ) //current is a leaf....
{
//do nothing! base case!! party down!
}
else if( items[current] <= items[minChild(current)] ) //no violation..
{
//done!1 party down! base case
}
else
{
//step 1: swap with min child
int mchild = minChild(current);
swap( items[current], items[mchild] );
//step 2: continue bubbling down
bubbleDown(mchild);
}
}
public:
minHeap(int cap)
{
items = new THING[cap];
n=0;
}
//return true if heap is empty
bool empty()
{
if( n==0 )
return true;
else
return false;
}
//add item x to heap
void insert(THING x)
{
//step 1: add x to end of array
items[n] = x;
n++;
//step 2: bubble up!
bubbleUp(n-1);
}
//remove and return smallest item in heap
THING extractMin()
{
//step 1: store root item in output box
THING output = items[0];
//step 2: put last item at root
items[0] = items[n-1];
n--;
//step 3: bubble down!
bubbleDown(0);
return output;
}
};
vertex *dog = new vertex(0,0,0);
vertex *cat = new vertex(0,0,0);
if(dog < cat)
Compares two pointers and effectively the addresses. Comparing addresses does not make much sense as they can have any values.
You need to compare two objects:
if(*dog < *cat)
Ofcourse you also need to change the function prototype of the overloaded operator to take this in to account.
vertex & vertex::operator=(vertex * z)
That is an assignment operator that takes a left hand side of type vertex and a right hand side of type vextex*. The usual signature for operator= is:
vertex& operator=(const vertex& rhs);
The latter definition allows for assignment of one object to another object, while the former assigns a pointer to an object.