I have a class called MinPQ (priority queue) which works on generic data called Item. Out of the greater() method, other methods are doing work on the indexes of the items.
The greater() method is comparing two different items - see bellow.
This method will work fine for any standard data type (Item = int, float, etc...) but what about a user defined object?
How can I modify this MinPQ class and the greater() method in order to take into account a more general Object?
The MinPQ class:
template <class Item> class MinPQ
{
private:
Item *items;
int N;
int queueSize;
void resize(int capacity);
void swim(int k);
bool greater(int i, int j);
void exch(int i, int j);
void sink(int k);
public:
MinPQ();
MinPQ(const MinPQ &pq);//copy constructor
~MinPQ();
void insert(Item item);
Item min();
inline int size(){return N-1;}
inline bool isEmpty(){return size() == 0;}
void print();
};
the constructors:
template <class Item> MinPQ<Item>::MinPQ(const MinPQ &pq)
{
N = pq.N;
queueSize = pq.queueSize;
items = new Item[queueSize];
for(int i = 0; i < N; ++i)
items[i] = pq.items[i];
}
template <class Item> MinPQ<Item>::MinPQ()
{
queueSize = 2;
items = new Item[queueSize];
N = 1;
}
The greater() method:
template <class Item> bool MinPQ<Item>::greater(int i, int j)
{
return items[i] > items[j];
}
Having the definition of SomeItem you can specify that operator > will do with two items:
struct SomeItem
{
//item stuff
int item_property;
};
bool operator > (const SomeItem & a,const SomeItem & b)
{
return a.item_property > b.item_property;
}
//after this you can compare items based on item_property.
//...
MinPQ<SomeItem> a;
a.greather(0,1);//this will work as long as types used int MinPQ will have operator >
Or you can overload the operator directly inside the type:
struct SomeItem
{
//item stuff
int item_property;
bool operator > (const SomeItem & other)const
{
return item_property > other.item_property;
}
};
Related
I create a class Vector that contain two variables that are template variable, I am trying to build such a dictionary that tell mark of a specific student.
The problem is I am struggling dynamic allocating memory with template. I have to do this without map or STL help. Can you explain, how to allocate them properly.
#define DEF_CAPACITY 20
template <class U, class T>
class Vector {
protected:
T* _data;
U* _keys;
int _size; //size in use
int _capacity; //available capacity
public:
//constructors
Vector(int capacity = DEF_CAPACITY);
~Vector();
int getSize() const { return size; }
void insert(U key, T data);
T operator[](U key);
};
template<class U, class T>
inline Vector<U, T>::Vector(int capacity)
{
this->_capacity = capacity;
this->_size = 0;
}
template<class U, class T>
Vector<U, T>::~Vector()
{
if (_data)
delete[] _data;
if (_keys)
delete[] _keys;
}
template<class U, class T>
void Vector<U, T>::insert(U key, T data)
{
_keys[_size] = new U;
//Maybe I have to do something like that, but all options I test doesn't work
//keys[_size] = new U[Some size];
_keys[_size] = key;
_data[_size] = new T;
_data[_size] = data;
_size++;
}
template<class U, class T>
T Vector<U, T>::operator[](U key)
{
int index = 0;
for (int i = 0; i < size; i++)
if (_keys[i] == key)
index = i;
return _data[index];
}
int main() {
Vector<string, int> grades;
grades.insert("john", 90);
grades.insert("marc", 100);
grades.insert("ron", 87);
grades.insert("lynda", 95);
//...
grades.insert("Tome", 93);
//...
cout << grades["marc"] << endl;
cout << grades["lynda"] << endl;
cout << grades["john"] << endl;
return 0;
}
To allocate n elements of type T you use:
T* array = new T[n];
so to allocate space for your keys and values:
// be aware: this will call the constructor for each element!!!
_keys = new U[n];
_data = new T[n];
If your "Vector" has a fixed capacity, this should be done in your constructor:
template<class U, class T>
inline Vector<U, T>::Vector(int capacity)
: _data(new T[capacity]);
, _keys(new U[capacity]);
, _size(0);
, _capacity(capacity);
{
}
after that, you can insert key/value pairs like this:
template<class U, class T>
void Vector<U, T>::insert(const U& key, const T& data)
{
if(_size == _capacity)
throw std::out_of_range("no space left!!!");
_keys[_size] = key; // copy assignment
_data[_size] = data; // copy assignment
_size++;
}
This design will unnecessarily call constructors for unused keys and values.
You could also do this with malloc and free to prevent this, though I wouldn't recommend going that way and instead use the standard library.
I'm trying to implement a generic heap in C++. In order to make it generic as possible I'm trying to allow the heap to take a comparator to allow different kinds of heap ordering. However I've never used comparators before and I'm running into an issue. Here is the the setup for my heap.
template <typename T>
class greater {
public:
bool operator()(const T& a, const T& b) const { return a > b; }
};
template <typename T, typename C = greater<T> >
class heap {
public:
//constructors
heap();
heap(const heap& other);
heap& operator= (const heap& other);
//destructor
~heap();
//operations
void push(const T& datum);
T& peek() const;
void pop();
//status
bool empty() const { return tree.empty(); }
int size() const { return tree.size(); }
//debug
void print() const;
private:
std::vector<T> tree;
//auxilliary functions
int parent(int index) { return (index - 1) / 2; }
int left(int index) { return 2 * index; }
int right(int index) { return 2 * index + 1; }
void swap(int a, int b) {
T temp = tree[a];
tree[a] = tree[b];
tree[b] = temp;
}
void bubble_up(int index);
void bubble_down(int index);
};
But for my implementation of the bubble_up method I get the following Visual Studio Error: 'compare':function does not take 2 arguments | Error Code:C2660
The error references the line of the while loop in the implementation which is shown below.
template <typename T, typename C>
void heap<T, C>::bubble_up(int index) {
C compare;
int parent_index = parent(index);
while (compare(tree[parent_index], tree[index]) && parent_index >= 0) {
swap(parent_index, index);
index = parent_index;
parent_index = parent(index);
}
}
I'm sure that I've handled using the comparison function poorly, but I'm struggling to find a clear explanation for why this is wrong from my googling so any advice would be appreciated.
There are some Classes: Array, NumericArray. Array is a template class, and NumericArray is a class inherited from Array designed to take int, double, etc.
Part of Header of NumericArray:
template <class T = int>
class NumericArray : public Array<T>{
private:
T* m_data;
int size;
public:
NumericArray<T> operator * (T factor)const;
};
here are constructors and some functions of NumericArray:
template <class T>
NumericArray<T>::NumericArray(){
m_data = new T[10];
size = 10;
}
template <class T>
NumericArray<T>::NumericArray(int n){
m_data = new T[n];
size = n;
}
template <class T>
NumericArray<T>::NumericArray(const NumericArray<T>& s_data){
m_data = new T[s_data.size];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = s_data.m_data[i];
}
size = s_data.Size();
}
/* Destructor */
template <class T>
NumericArray<T>::~NumericArray(){
delete [] m_data;
}
template <class T>
NumericArray<T> NumericArray<T>::operator * (T factor)const{
NumericArray<T> temp(size);
for (int i = 0; i<size;i++){
temp.m_data[i] = (*this)[i] *factor;
}
return temp;
}
And when I call it in the main(), something weird happens. For example:
NumericArray<int> intArray1(10);
NumericArray<int> intArray2;
for(int i =0; i<10;i++){
intArray1[i] = i;
intArray2[i] = i;
}
The 2 arrays do contain numbers 0-9, but if I call
NumericArray intArray4 = intArray1*2;
intArray4 consists of zero(0)s. It seems that the default constructor is called in the function and passed to Array4. And after the operator, Array1 and Array2 are still numbers 0-9
Below are the related code of Array
template class Array{
private:
T* m_data;
int size;
public:
Array(); // constructor
Array(int n); // constructor
Array(const Array<T>& s_data); //Copy Constructor
virtual ~Array(); // destructor
void SetElement(int i, const T& source);
T& GetElement(int i)const;
int Size() const;
int DefaultSize()const;
void DefaultSize(int n);
// Operator overloading
Array<T>& operator = (const Array<T>& source) ;
T& operator [](int i);
const T& operator [] (int i) const;
};
template <class T>
Array<T>::Array(){
// default constructor
m_data = new T[defaultSize]; // initialize T*
size = defaultSize; // initialize integer
}
template <class T>
Array<T>::Array(int n){
// Constructor with arguments
m_data = new T[n];
size = n;
}
template <class T>
Array<T>::Array(const Array<T>& s_data){
// Copy constructor
m_data = new T[s_data.Size()];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = T( s_data.m_data[i]);
}
size = s_data.Size();
defaultSize = s_data.Size();
}
template <class T>
T& Array<T>::operator [](int i) {
if (i > size|| i<0){
OutOfBoundsException a;
throw a;
}
return m_data[i];
}
Not sure if provided enough information. Any hint is greatly appreciated.
The easiest way to access base class data members when the base is a (dependent) class template, is a using declaration like this:
#include <iostream>
using namespace std;
template< class Item >
class Base
{
protected:
Item item_;
Base( Item const& v ): item_( v ) {}
};
template< class Item >
class Derived
: public Base< Item >
{
protected:
using Base<Item>::item_;
public:
auto value() const -> Item { return item_; }
Derived( Item const& v ): Base<Item>( v ) {}
};
auto main() -> int
{
Derived<int> const x( 42 );
cout << x.value() << endl;
}
Alternatively you can qualify the access, e.g. this->item_ or Base<Item>::item_.
That said, it’s usually not a good idea to let derived classes access base class data members directly.
Here is the problem: both NumericArray and Array have
T* m_data;
int size;
The function Array::operator[] is called from Array which uses Array::m_data, however the NumericArray::operator* sets NumericAray::m_data. It probably is working as you would expect, but you are reading from the wrong pointer.
Remove the members from NumericArray and make the members protected instead of private in Array. The second part is optional if the implementation is changed a little bit.
How do I access the variables itemtype and total within the increment function? The code I have below gives me errors as follows
Counter2.h: In member function ‘int Counter::increment(T)’:
Counter2.h:28:31: error: ‘itemtype’ was not declared in this scope
Counter2.h:36:22: error: ‘itemtype’ was not declared in this scope
Counter2.h:36:39: error: ‘total’ was not declared in this scope
I must be able to use the command Counter<T> counter; where T can be any type, such as string and counter.increment()
#include<string>
//#include<cstdlib>
#include<vector>
using std::vector;
using std::string;
template<class T>
class Record{
public:
T itemtype;
int total;
};
template<class T>
class Counter{
vector< Record<T> > data;
public:
int increment(T item);
int count(T item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(T item){
bool check = false;
for(int i=0; i < data.size(itemtype); i++){
if(data[i].itemtype == item){
data[i].total++;
bool check = true;
break;
}
}
if(check == false){
data.push_back(itemtype = item, total = 1);
}
}
int main(){
Counter<string> counter;
counter.increment("orange");
counter.increment("orange");
return 0;
}
In line for(int i=0; i < data.size(itemtype); i++){
will be: for(int i=0; i < data.size(); i++){
And data.push_back(itemtype = item, total = 1); can be:
data.push_back({item, 1}); // by using initializer list ; C++11
or,
Record r;
r.itemtype = item;
r.total = 1;
data.push_back(r);
You can look at : http://www.cplusplus.com/reference/vector/vector/
to know about std::vector.
I'm not too sure I understand what you're after here, though for a start you're trying to access private members of class Record. You could make record a struct (public by default), or provide getters/setters or alternatively add:
friend class Counter;
to Record so that Counter can access its private members.
You can make Record a private structur inside Counter. That will not expose it implementation. You need to change also how you acces data. It is a vector of Record, not a Record. Something like:
template<class T>
class Counter
{
struct Record{ T itemtype; int total; };
vector< Record > data;
public:
int increment(const T& item);
int count(const T& item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(const T& item)
{
auto i=data.begin();
i= find(i,data.end(),[&item](const Record& r)
{return item==r.itemtype;});
if (i!=data.end())
return ++(i->total);
data.push_back({item, 1});
return 1;
}
If you dont like the lambda fun:
template<class T>
int Counter <T> :: increment(const T& item)
{
for(int i=0; i < data.size(); ++i)
if(data[i].itemtype == item)
return ++(data[i].total);
data.push_back({item, 1});
return 1;
}
But i think what you actually need is a multiset (if you dont care about the order). Something like this:
template<class T>
class Counter
{
std::multiset <T> data;
public:
int increment(T item);
int count(T item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(T item)
{
data.insert(item);
return data.count(item);
}
I am attempting to define the concrete class arrayList by extending the abstract class linearList.
My header for defining the class is as follows:
class arrayList : public linearList
I am given the error at line 4: error C2143: syntax error : missing ',' before '<'
This also happens when I define chain by extending linearList.
I made sure to use namespace std and include all necessary files. There are no errors in the linearList class so I think it's an error in arrayList.
I am also getting the error "see reference to class template instantiation 'arrayList' being compiled" at line 27 (marked in code). Both arrayList and linearList are included below.
ArrayList
#include <iostream>
using namespace std;
template<class T>
class arrayList : public linearList<T>
{
public:
// constructor, copy constructor and destructor
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>&);
~arrayList() {delete [] element;}
// ADT methods
bool empty() const {return listSize == 0;}
int size() const {return listSize;}
T& get(int theIndex) const;
int indexOf(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output(ostream& out) const;
// additional method
int capacity() const {return arrayLength;}
protected:
void checkIndex(int theIndex) const;
// throw illegalIndex if theIndex invalid
T* element; // 1D array to hold list elements
int arrayLength; // capacity of the 1D array
int listSize; // number of elements in list
}; //line 28
template<class T>
arrayList<T>::arrayList(int initialCapacity)
{
// Constructor.
if (initialCapacity < 1)
{
ostringstream s;
s << "Initial capacity = " << initialCapacity << " Must be > 0";
throw illegalParameterValue(s.str());
}
arrayLength = initialCapacity;
element = new T[arrayLength];
listSize = 0;
}
template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
// Copy constructor.
arrayLength = theList.arrayLength;
listSize = theList.listSize;
element = new T[arrayLength];
copy(theList.element, theList.element + listSize, element);
}
template<class T>
void arrayList<T>::checkIndex(int theIndex) const
{
// Verify that theIndex is between 0 and
// listSize - 1.
if (theIndex < 0 || theIndex >= listSize)
{
ostringstream s;
s << "index = " << theIndex << " size = "
<< listSize;
throw illegalIndex(s.str());
}
}
template<class T>
T& arrayList<T>::get(int theIndex) const
{
// Return element whose index is theIndex.
// Throw illegalIndex exception if no such
// element.
checkIndex(theIndex);
return element[theIndex];
}
template<class T>
int arrayList<T>::indexOf(const T& theElement)const
{
// Return index of first occurrence of theElement.
// search for theElement
int theIndex = (int) (find(element, element
+ listSize, theElement) - element);
// check if theElement was found
if (theIndex == listSize)
return -1; // not found
else return theIndex;
}
template<class T>
void arrayList<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.
checkIndex(theIndex);
// valid index, shift elements with higher
// index
copy(element + theIndex + 1, element +
listSize,element + theIndex);
element[--listSize].~T(); // invoke destructor
}
template<class T>
void arrayList<T>::insert(int theIndex, const T& theElement)
{
// Insert theElement.
if (theIndex < 0 || theIndex > listSize)
{// invalid index
// code to throw an exception comes here
}
// valid index, make sure we have space
if (listSize == arrayLength)
{
// no space, double capacity
changeLength1D(element, arrayLength,
2 * arrayLength);
arrayLength *= 2;
}
// shift elements right one position
copy_backward(element + theIndex,
element + listSize,
element + listSize + 1);
element[theIndex] = theElement;
listSize++;
}
template<class T>
void arrayList<T>::output(ostream& out) const
{
// Put the list into the stream out.
copy(element, element + listSize,
ostream_iterator<T>(out, " "));
}
template <class T>
ostream& operator<<(ostream& out, const arrayList<T>& x)
{x.output(out); return out;}
LinearList
#include <ostream>
using namespace std;
template<class T>
class linearList
{
public:
virtual ~linearList() {}
virtual bool empty() const = 0;
virtual int size() const = 0;
virtual T& get(int theIndex) const = 0;
virtual int indexOf(const T& theElement)const = 0;
virtual void erase(int theIndex) = 0;
virtual void insert(int theIndex,const T& theElement) = 0;
virtual void output(ostream & out) const = 0;
};
lori has the right answer, but just in case it's not clear:
arrayList inherits from linearList, so it's impossible to define arrayList without also knowing the definition of linearList. This is why the compiler is complaining at line 4; it doesn't yet know about linearList. using namespace std is irrelevant to this problem, and by the way it's bad practice to have using statements in header files.
Assuming that your "ArrayList" code sample is in array_list.h and "LinearList" in linear_list.h, you should change the first few lines of array_list.h to this:
#include <iostream>
#include "linear_list.h"
template<class T>
class arrayList : public linearList<T>
{
public:
...