I have a template class that I am testing:
class SparseMat {
private:
FHvector<FHlist<MatNode<Object>>> matrix;
int numOfRows, numOfCols;
const Object defaultValue;
public:
SparseMat(int r, int c, const Object& defaultVal);
const Object & get(int r, int c) const;
bool set(int r, int c, const Object& x);
};
template <class Object>
SparseMat<Object>::SparseMat(int r, int c, const Object& defaultVal) : defaultValue(defaultVal) {
numOfRows = r;
numOfCols = c;
matrix.resize(numOfRows);
for (int counter = 0; counter < numOfRows; counter++) {
FHlist<MatNode<Object>> currentRow;
matrix.push_back(currentRow);
}
}
template <class Object>
bool SparseMat<Object>::set(int r, int c, const Object& x) {
if (r >= numOfRows || r < 0 || c < 0 || c >= numOfCols) {
return false;
}
if (r == 9 && c == 9) {
cout << x << endl;
}
if (r == 9 && c == 9) {
cout << x << endl;
}
for (FHlist<MatNode<Object>>::iterator iter = matrix[r].begin(); iter != matrix[r].end(); ++iter) {
if ((*iter).getCol() == c) {
if (x == defaultValue) {
matrix[r].erase(iter);
return true;
}
else {
(*iter).data = x;
return true;
}
}
}
matrix[r].push_back(MatNode<Object>(c, x));
return true;
}
template <class Object>
const Object & SparseMat<Object>::get(int r, int c) const {
if (r >= numOfRows || r < 0 || c < 0 || c >= numOfCols) {
throw OutOfBoundsException();
}
FHlist<MatNode<Object>> wantedRow = matrix[r];
for (FHlist<MatNode<Object>>::iterator iter = wantedRow.begin(); iter != wantedRow.end(); ++iter) {
if ((*iter).getCol() == c) {
return (*iter).getData();
}
}
return NULL;
}
MatNode is as follows:
template <class Object>
class MatNode
{
protected:
int col;
public:
Object data;
MatNode(int cl = 0, Object dt = Object()) : col(cl), data(dt) { }
int getCol() const { return col; }
const Object & getData() const {return data; }
};
The immensely strange thing is my two outputs print two different things. The first prints 21, as expected. The second prints out some random float, which is definitely not expected as I have changed nothing with x between the two outputs.
#include <iostream>
using namespace std;
#include "FHsparseMat.h"
#define MAT_SIZE 100000
typedef SparseMat<float> SpMat;
int main()
{
SpMat mat(MAT_SIZE, MAT_SIZE, 0);
mat.set(3, 9, 21);
cout << mat.get(3, 9) << endl;
mat.set(9, 9, 21);
cout << mat.get(9, 9) << endl;
mat.set(9, 9, mat.get(3,9));
cout << mat.get(9, 9) << endl;
}
Here is my tester. If I replace mat.get(3,9) with the hard coded value of 21, the issue disappears, if that helps.
get() has a return type of const Object &.
As a result, the final line of the function
return 0; // source code says NULL but preprocessor replaces that with 0
is returning a dangling reference to a temporary Object implicitly constructed with the value 0.
Using that dangling reference will, of course, cause undefined behavior.
It's not completely clear why that line is reached, but the logic that erases an item if you write the same value to the same location certainly seems suspicious. IMO you should only remove an item when the value written is zero.
The issue is that Object MatNode::getData() const is not returning a reference, and you are returning a reference in const Object & SparseMat<Object>::get(int r, int c) const. Change it to:
Object SparseMat<Object>::get(int r, int c) const.
Related
I have a list of {a,b} and i need all possible combinatations where say n=3.
so:
[a,b,a],
[b,a,b]
[a,a,a]
[b,b,b]
etc.
Is there a name of such a problem
My current solution just uses random sampling and is very inefficient:
void set_generator(const vector<int>& vec, int n){
map<string, vector<int>> imap;
int rcount = 0;
while(1){
string ms = "";
vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
cout << ms << endl;
}
}
set_generator({1,2},3);
Let us call b the size of the input vector.
The problem consists in generating all numbers from 0 to b^n - 1, in base b.
A simple solution increments the elements of an array one by one, each from 0 to b-1.
This is performed by the function increment in the code hereafter.
Output:
111
211
121
221
112
212
122
222
The code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
void set_generator_op (const std::vector<int>& vec, int n){
std::map<std::string, std::vector<int>> imap;
int rcount = 0;
while(1){
std::string ms = "";
std::vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
std::cout << ms << "\n";
}
}
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
void set_generator_new (const std::vector<int>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
while (true) {
std::string permut = "";
for (auto &k: cpt) {
permut += std::to_string (vec[k]);
}
std::cout << permut << "\n";
if (!increment(cpt, base)) return;
}
}
int main() {
set_generator_op ({1,2},3);
std::cout << "\n";
set_generator_new ({1,2},3);
}
Following advices of Jarod42, I have
suppressed the useless conversion to a string
used a more elegant do ... while instead of the while true
inversed the iterators for printing the result
Moreover, I have created a templated version of the program.
New output:
111
112
121
122
211
212
221
222
aaa
aab
aba
abb
baa
bab
bba
bbb
And the new code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
template <typename T>
void set_generator_new (const std::vector<T>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
do {
for (auto it = cpt.rbegin(); it != cpt.rend(); ++it) {
std::cout << vec[*it];
}
std::cout << "\n";
} while (increment(cpt, base));
}
int main() {
set_generator_new<int> ({1,2}, 3);
std::cout << "\n";
set_generator_new<char> ({'a','b'}, 3);
}
Besides the concrete answer for integer usage, I want to provide a generic way I needed during test case construction for scenarios with a wide spread of various parameter variations. Maybe it's helpful to you too, at least for similar scenarios.
#include <vector>
#include <memory>
class SingleParameterToVaryBase
{
public:
virtual bool varyNext() = 0;
virtual void reset() = 0;
};
template <typename _DataType, typename _ParamVariationContType>
class SingleParameterToVary : public SingleParameterToVaryBase
{
public:
SingleParameterToVary(
_DataType& param,
const _ParamVariationContType& valuesToVary) :
mParameter(param)
, mVariations(valuesToVary)
{
if (mVariations.empty())
throw std::logic_error("Empty variation container for parameter");
reset();
}
// Step to next parameter value, return false if end of value vector is reached
virtual bool varyNext() override
{
++mCurrentIt;
const bool finished = mCurrentIt == mVariations.cend();
if (finished)
{
return false;
}
else
{
mParameter = *mCurrentIt;
return true;
}
}
virtual void reset() override
{
mCurrentIt = mVariations.cbegin();
mParameter = *mCurrentIt;
}
private:
typedef typename _ParamVariationContType::const_iterator ConstIteratorType;
// Iterator to the actual values this parameter can yield
ConstIteratorType mCurrentIt;
_ParamVariationContType mVariations;
// Reference to the parameter itself
_DataType& mParameter;
};
class GenericParameterVariator
{
public:
GenericParameterVariator() : mFinished(false)
{
reset();
}
template <typename _ParameterType, typename _ParameterVariationsType>
void registerParameterToVary(
_ParameterType& param,
const _ParameterVariationsType& paramVariations)
{
mParametersToVary.push_back(
std::make_unique<SingleParameterToVary<_ParameterType, _ParameterVariationsType>>(
param, paramVariations));
}
const bool isFinished() const { return mFinished; }
void reset()
{
mFinished = false;
mNumTotalCombinationsVisited = 0;
for (const auto& upParameter : mParametersToVary)
upParameter->reset();
}
// Step into next state if possible
bool createNextParameterPermutation()
{
if (mFinished || mParametersToVary.empty())
return false;
auto itPToVary = mParametersToVary.begin();
while (itPToVary != mParametersToVary.end())
{
const auto& upParameter = *itPToVary;
// If we are the very first configuration at all, do not vary.
const bool variedSomething = mNumTotalCombinationsVisited == 0 ? true : upParameter->varyNext();
++mNumTotalCombinationsVisited;
if (!variedSomething)
{
// If we were not able to vary the last parameter in our list, we are finished.
if (std::next(itPToVary) == mParametersToVary.end())
{
mFinished = true;
return false;
}
++itPToVary;
continue;
}
else
{
if (itPToVary != mParametersToVary.begin())
{
// Reset all parameters before this one
auto itBackwd = itPToVary;
do
{
--itBackwd;
(*itBackwd)->reset();
} while (itBackwd != mParametersToVary.begin());
}
return true;
}
}
return true;
}
private:
// Linearized parameter set
std::vector<std::unique_ptr<SingleParameterToVaryBase>> mParametersToVary;
bool mFinished;
size_t mNumTotalCombinationsVisited;
};
Possible usage:
GenericParameterVariator paramVariator;
size_t param1;
int param2;
char param3;
paramVariator.registerParameterToVary(param1, std::vector<size_t>{ 1, 2 });
paramVariator.registerParameterToVary(param2, std::vector<int>{ -1, -2 });
paramVariator.registerParameterToVary(param3, std::vector<char>{ 'a', 'b' });
std::vector<std::tuple<size_t, int, char>> visitedCombinations;
while (paramVariator.createNextParameterPermutation())
visitedCombinations.push_back(std::make_tuple(param1, param2, param3));
Generates:
(1, -1, 'a')
(2, -1, 'a')
(1, -2, 'a')
(2, -2, 'a')
(1, -1, 'b')
(2, -1, 'b')
(1, -2, 'b')
(2, -2, 'b')
For sure, this can be further optimized/specialized. For instance you can simply add a hashing scheme and/or an avoid functor if you want to avoid effective repetitions. Also, since the parameters are held as references, one might consider to protect the generator from possible error-prone usage via deleting copy/assignement constructors and operators.
Time complexity is within the theoretical permutation complexity range.
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.
I have a simple code that compares couple values. I'm using template function to reduce the amount of code, so i overloaded function twice(for different cases).
//cmp.h
template <class T>
bool cmp(T x,T y)
{
if(x == y)
{
return true;
}else
return false;
}
template <class T>
bool cmp(T *x,T *y)
{
if(*x==*y)
{ return true;}else
return false;
}
//main.cpp
#include <iostream>
#include <string>
#include "cmp.h"
using std::cout;
using std::endl;
using std::string;
int main() {
int aInt = 1, bInt = 2;
double aDouble = 3.0, bDouble = 3.0;
char aChars[5] = "haha", bChars[5] = "hahb";
char taChars[6] = "trick", tbChars[6] = "trick";
string aStr = "haha", bStr = "aha";
int* aIntPtr = &aInt, *bIntPtr = &bInt;
cout << cmp(aInt, bInt)<< endl;
cout << cmp(aDouble, bDouble)<< endl;
cout << cmp(aChars, bChars)<< endl;//i can't figure out why char prints out true here ???
cout << cmp(taChars, tbChars)<< endl;
cout << cmp(aStr, bStr)<< endl;
cout << cmp(aIntPtr, bIntPtr)<< endl;
cout << cmp(&aDouble, &bDouble) << endl;
return 0;
}
My output is:
0
1
1
1
0
0
1
And i expected:
0
1
0
1
0
0
1
Why it shows that two strings are identical ? Why if i entirely change the word, lets say
char aChars[5] = "jack", bChars[5] = "hahb";
then only it gives the right result. Isn't my second overloaded function should handle this right? (bool cmp(T *x,T *y))
Why it shows that two strings are identical ?
Because
template <class T>
bool cmp(T *x,T *y)
{
if(*x == *y)
{
return true;
}else
return false;
}
check only the first value pointed by x and y.
So when you check
char aChars[5] = "haha", bChars[5] = "hahb";
cout << cmp(aChars, bChars)<< endl;//
check that h is equal to h.
If you want check the equality between strings (and if you want avoid the use of the good-old std::strcmp()) you have to check all characters until the first zero.
But this is true for old style C-string; I don't think it's a good idea to develop a function that check equality between pointer for a generic type T.
-- EDIT --
Could u guide me please
To give an example... it's a lot of time that I don't think in plain C but something as follows should works
bool cmp (char const * p1, char const * p2)
{
for ( ; *p1 && *p1 == *p2 ; ++p1, ++p2 )
;
return *p1 == *p2;
}
Off Topic: you write code as
bool cmp(T *x,T *y)
{
if(*x==*y)
{ return true;}else
return false;
}
It's equivalent to
bool cmp(T *x,T *y)
{ return *x == *y; }
More generally speaking... if you have a code of type
if ( someTest )
return true;
else
return false;
and the function return a bool (or someTest is of type bool), you can write (and, IMHO, is more readable and elegant) simply write
return someTest;
Why it shows that two strings are identical ?
Array decays to pointer, so char taChars[6] will use overload template <class T>
bool cmp(T *x,T *y) and so compare only first element (which are equal in your case).
In C++17, you might do:
template <typename T>
bool cmp(const T& lhs, const T& rhs)
{
if constexpr (std::is_pointer<T>::value) {
return *lhs == *rhs;
} else if constexpr (std::is_array<T>::value) {
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs));
} else {
return lhs == rhs;
}
}
Demo
This is what I have so far. It throws an exception when I try to access an index out of bounds. I tried to say "return NULL" if the range is out of bounds for the overloaded subscript operator, but it's not working. The problem is when I try to assign a value to an index above the upper limit it allows it to happen. Like with the current code if I change the "< 8" in the main function to "< 9", it uses array element 8 without problem, but I want it to have a problem with that. Any help is appreciated.
#include <iostream>
#include <stdexcept>
using namespace std;
//L for lower-bound, U for upper-bound
template <typename T, int L, int U>
class LBArray
{
public:
LBArray()
{
lbound = L;
ubound = U;
data = new T[ubound - lbound];
}
T& operator[](int index)
{
if (index < lbound || index > ubound)
{
throw out_of_range("index out of bounds");
}
return data[index - lbound];
}
~LBArray()
{
if (data) delete[] data;
}
private:
T *data;
int lbound;
int ubound;
};
int main(int argc, char** argv)
{
LBArray<int, 5, 7> data;
cout << "LBArray<int, 5, 7> data\n";
for (int x = 5; x < 8; x++)
{
data[x] = x;
cout << endl << "data[" << x << "] = " << data[x];
}
return 0;
}
You create array from 5 to 7, and I suppose that 5 and 7 included, then you have 3 elements data[5], data[6], data[7], but in your code:
data = new T[ubound - lbound];
and that 2 elements 7-5 = 2. You lose one element.
Therefore I think you need do like that:
data = new T[ubound - lbound + 1];
After that change all work fine, but you do not use try..catch, then your code shutdown.
If you do not want to use try..catch, I offer to you next code:
T& operator[](int index)
{
if (index < lbound || index > ubound)
{
T nullVar = NULL;
return (T&)nullVar;
}
return data[index - lbound];
}
Attempting to get element with wrong index the function return NULL.
Here is an implementation that uses std::vector as the underlying container:
#include <iostream>
#include <stdexcept>
#include <vector>
template <typename T, size_t L, size_t U>
class LBArray
{
std::vector<T> data;
void checkIndex(size_t index)
{
if ( index < L || index >= U )
throw out_of_range("index out of bounds");
}
public:
LBArray() : data(U - L) {}
T& operator[](size_t index)
{
checkIndex(index);
return data[index - L];
}
T& operator[](size_t index) const
{
checkIndex(index);
return data[index - L];
}
};
using namespace std;
int main()
{
LBArray<int, 5, 7> data;
cout << "LBArray<int, 5, 7> data\n";
for (int x = 5; x < 8; x++)
{
data[x] = x;
cout << endl << "data[" << x << "] = " << data[x];
}
}
Note that the operator[] is overloaded for both const and non-const access. Also, the LBArray class can now be safely copied since the std::vector does the memory management.
I am trying to simulate Conway's game of life using an implementation file I created, I have made good progress but unfortunately I am getting an error which confuses me. I think the problem is ignorance on my part of how to properly code templated functions, anyways this is my implementation file:
#include <list>
#ifndef HashTable_h
#define HashTable_h
using namespace std;
#define HASHTABLE_CAPACITY 1009
template <class DataType>
class HashTable
{
public:
HashTable(); // constructor
bool insert(DataType &a); // insert function for inserting value of dataType into table
bool retrieve(DataType &a); // retrieve function for retrieving value from table
bool replace(DataType &a); // function for replacing the value from the table with the parameter
bool remove(DataType& a);//removed function written and checked
//int getSizeOf() const;
void clear(); // for clearing the table
int size() const;
private:
list<DataType> table[HASHTABLE_CAPACITY]; // static array
int count;
int currentIndex;
typename list<DataType>::const_iterator it;
};
// constructor
template <class DataType>
HashTable<DataType>::HashTable()
{
list<DataType> table[HASHTABLE_CAPACITY];
count = 0;
currentIndex = -1;
}
// retrieve function
template <class DataType>
bool HashTable<DataType>::retrieve(DataType &a)
{
// get wrapped index
int wrappedIndex = a.hashCode() % HASHTABLE_CAPACITY;
if (wrappedIndex < 0) wrappedIndex = wrappedIndex + HASHTABLE_CAPACITY;
// if the array location isn't occupied, fail
if (wrappedIndex < 0 || wrappedIndex >= HASHTABLE_CAPACITY || table[wrappedIndex].empty()) return false;
// iterator for traversing table values
typename list<DataType>::const_iterator it;
// if the keys match then replace the data
// if a collision occurs then return false
it = find(table[wrappedIndex].begin(), table[wrappedIndex].end(), a);
if(it == table[wrappedIndex].end())
return false;
a = *it;
return true;
}
// overloaded operator function
// function for inserting values
template <class DataType>
bool HashTable<DataType>::insert(DataType &value)
{
// get wrapped index
int wrappedIndex = value.hashCode() % HASHTABLE_CAPACITY;
if (wrappedIndex < 0) wrappedIndex = wrappedIndex + HASHTABLE_CAPACITY;
// iterator for traversing values in table
typename list<DataType>::iterator it;
// if array location is not "occupied", copy into array
// else if keys match, replace the data
if (table[wrappedIndex].empty())
{
table[wrappedIndex].push_back(value);
count++;
return true;
}
else
{
it = find(table[wrappedIndex].begin(), table[wrappedIndex].end(), value);
if (it != table[wrappedIndex].end()) *it = value;
else {table[wrappedIndex].push_back(value); count++;}
}
return true;
}
// function for replacing values
template <class DataType>
bool HashTable<DataType>::replace(DataType &value)
{
// get wrapped index
int wrappedIndex = value.hashCode() % HASHTABLE_CAPACITY;
if (wrappedIndex < 0) wrappedIndex = wrappedIndex + HASHTABLE_CAPACITY;
if(table[wrappedIndex].empty()) return false;
// iterator for traversing the values in table
typename list<DataType>::const_iterator it;
it = find(table[wrappedIndex].begin(), table[wrappedIndex].end(), value);
if(it == table[wrappedIndex].end()) return false;
value = *it;
table[wrappedIndex].erase(it);
count--;
return true;
}
template <class DataType>
bool HashTable<DataType>::remove(DataType &value)
{
// get wrapped index
int wrappedIndex = value.hashCode() % HASHTABLE_CAPACITY;
if (wrappedIndex < 0) wrappedIndex = wrappedIndex + HASHTABLE_CAPACITY;
if(table[wrappedIndex].empty()) return false;
// iterator for traversing the values in table
typename list<DataType>::iterator it;
// if array location is not "occupied", copy into array
// else if keys match, remove the data
it = find(table[wrappedIndex].begin(), table[wrappedIndex].end(), value);
if(it == table[wrappedIndex].end()) return false;
value = *it;
table[wrappedIndex].erase(it);
count--;
return true;
}
// function for clearing the table of it's values
template <class DataType>
void HashTable<DataType>::clear()
{
count = 0;
currentIndex = -1;
for(int i = 0; i < HASHTABLE_CAPACITY; i++)
if( !table[i].empty()) table[i].clear();
}
template <class DataType>
int HashTable<DataType>::size() const
{
return count;
}
#endif
And this is the actual Game Of Life driver file:
// Lab 11b
#include <iostream>
using namespace std;
struct cell
{
int value; // equal to 1, so 0,0 is not a blank
int row; // any +/0/- value
int col; // any +/0/- value
bool operator==(const cell& c) const {return row == c.row && col == c.col;}
bool operator<(const cell& c) const {return (1000000 * row + col) < (1000000 * c.row + c.col);}
int hashCode() const {return 31 * row + col;}
};
#include "HashTable.h"
HashTable<cell> grid;
HashTable<cell> newGrid;
const int MINROW = -25;
const int MAXROW = 25;
const int MINCOL = -35;
const int MAXCOL = 35;
int neighborCount(int row, int col)
{
cell temp;
int count = 0;
for (temp.row = row - 1; temp.row <= row + 1; temp.row++)
for (temp.col = col - 1; temp.col <= col + 1; temp.col++)
if (temp.row != row || temp.col != col)
if (grid.retrieve(temp))
++count;
return count;
}
void initialize()
{
cout << "List the coordinates for living cells.\n";
cout << "Terminate the list with a special pair -1 -1\n";
cell temp;
while (true)
{
cin >> temp.row >> temp.col;
if (temp.row == -1 && temp.col == -1) break;
grid.insert(temp);
}
cin.ignore();
}
void print()
{
cell temp = {1};
cout << "\nThe current Life configuration is:\n";
for (temp.row = MINROW; temp.row <= MAXROW; temp.row++)
{
for (temp.col = MINCOL; temp.col <= MAXCOL; temp.col++)
if (grid.retrieve(temp))
cout << '*';
else
cout << ' ';
cout << endl;
}
cout << endl;
}
void update()
{
cell temp = {1};
newGrid.clear();
for (temp.row = MINROW; temp.row <= MAXROW; temp.row++)
for (temp.col = MINCOL; temp.col <= MAXCOL; temp.col++)
switch (neighborCount(temp.row, temp.col))
{
case 2:
if (grid.retrieve(temp)) newGrid.insert(temp);
break;
case 3:
newGrid.insert(temp);
break;
}
grid = newGrid;
};
int main()
{
cout << "Welcome to Conway's game of Life\n";
cout << "This game uses a grid in which\n";
cout << "each cell can either be occupied by an organism or not.\n";
cout << "The occupied cells change from generation to generation\n";
cout << "according to the number of neighboring cells which are alive.\n";
initialize();
print();
for (int i = 1; grid.size(); i++)
{
cout << "Generation " << i << ". Press ENTER to continue, X-ENTER to quit...\n";
if (cin.get() > 31) break;
update();
print();
}
return 0;
}
When I try to compile these files I get this error:
In file included from GameOfLife.cpp:16:
HashTable.h: In member function ‘bool HashTable<DataType>::retrieve(DataType&) [with DataType = cell]’:
GameOfLife.cpp:32: instantiated from here
HashTable.h:74: error: no matching function for call to ‘find(std::_List_iterator<cell>, std::_List_iterator<cell>, cell&)’
HashTable.h: In member function ‘bool HashTable<DataType>::insert(DataType&) [with DataType = cell]’:
GameOfLife.cpp:47: instantiated from here
HashTable.h:117: error: no matching function for call to ‘find(std::_List_iterator<cell>, std::_List_iterator<cell>, cell&)’
What could be the issue here?
You need to #include <algorithm> to get std::find. This is presumably what you want to use when you call find. You should avoid using namespace std, specially in headers.