Class template, no constructor could take the source(string) - c++

attempting to compile the code gives several errors(error codes at the bottom)
//heap.h
#include <iostream>
#include <vector>
using namespace std;
template<class TYPE>
class Heap{
private:
vector<TYPE> heap;
int size;// number of elements in the heap
bool maxheap = true;
TYPE bubble_up(TYPE item);
TYPE bubble_down(TYPE item);
public:
Heap();
Heap(bool maxheap);
Heap(vector<TYPE>, bool order);
~Heap();
void build_heap();
TYPE Insert(TYPE item);
TYPE Delete(TYPE& item);
const vector<TYPE> sort(bool order);
const vector<TYPE> sort();// defualt sort if no variable given, max sort
TYPE get_size();
void print_heap();
void clear_heap();
};
template<class TYPE>
Heap<TYPE>::Heap(){
TYPE dummy{};
heap.push_back(dummy);
size = heap.size() - 1;
}
template<class TYPE>
Heap<TYPE>::Heap(bool order){
maxheap = order; // true is max, false is min
TYPE dummy{};
heap.push_back(dummy);
size = heap.size() - 1;
}
template<class TYPE>
Heap<TYPE>::Heap(vector<TYPE> x, bool order){
maxheap = order;// true is max, false is min
TYPE tempSize;
TYPE dummy{};
heap.push_back(dummy);
size = heap.size() - 1;
tempSize = x.size();
for (TYPE y = 0; y < tempSize; y++){
heap.push_back(x[y]);
}
size = heap.size() - 1;
build_heap();
}
template<class TYPE>
TYPE Heap<TYPE>::Insert(TYPE item){
heap.push_back(item);
size = heap.size() - 1;
return bubble_up(size);
}
TYPE Heap<TYPE>::bubble_up(TYPE pos){
TYPE retVal;
if (pos == 1)// root of tree
{
return pos;
}
if (maxheap == true){
if (heap[pos] > heap[pos / 2]){// greater than parent
TYPE temp = heap[pos / 2]; //swap method
heap[pos / 2] = heap[pos];
heap[pos] = temp;
return retVal = bubble_up(pos / 2);
}
else{
return pos;
}
}
if (maxheap == false){//min heap
if (heap[pos] < heap[pos / 2]){// less than parent
TYPE temp = heap[pos / 2]; //swap method
heap[pos / 2] = heap[pos];
heap[pos] = temp;
return retVal = bubble_up(pos / 2);
}
else{
return pos;
}
}
}
here is the driver file currently being used.
#include <iostream>
#include <string>
#include "Heap.h"
using std::cout;
using std::endl;
typedef string TYPE;
int main(void) {
Heap<std::string> *s_heap = new Heap<std::string>(); // string heap
std::string s_item = "0";
vector<std::string> s_blah(11, s_item);
cout << "\n*** Test insert elements ***";
cout << endl << s_heap->Insert("15");
cout << endl << s_heap->Insert("1");
cout << endl << s_heap->Insert("3");
cout << endl << s_heap->Insert("4");
cout << endl;
}
full error code:
c:\users\\documents\visual studio 2013\projects\pa 3 templates\pa 3 templates\heap.h(85): error
C2664: 'std::string Heap<std::string>::bubble_up(TYPE)' : cannot convert argument 1 from 'int' to 'std::string'
1> with
1> [
1> TYPE=std::string
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
1> c:\users\\documents\visual studio 2013\projects\pa 3 templates\pa 3 templates\heap.h(82) : while compiling class template member function 'std::string Heap<std::string>::Insert(TYPE)'
1> with
1> [
1> TYPE=std::string
1> ]
1> c:\users\\documents\visual studio 2013\projects\pa 3 templates\pa 3 templates\driver.cpp(17) : see reference to function template instantiation 'std::string Heap<std::string>::Insert(TYPE)' being compiled
1> with
1> [
1> TYPE=std::string
1> ]

You've got a handful of problems here, mostly related to your attempt to make your Heap generic, which you've failed to do.
You're trying to create a heap of std::string (despite all the values you're adding being numbers, but lets skip that form the moment).
The argument of bubble_up will therefor also be a string:
TYPE Heap<TYPE>::bubble_up(TYPE pos){
The problem comes in lines like this:
if (pos == 1)// root of tree
and this:
heap[pos / 2] = heap[pos];
You're trying to compare a string with a number in the first case, and trying to perform division on the string in the second case! This isn't going to work. The problem can only get worse if you try to pass in structs and classes and whatever else.
You will either need to enforce that TYPE is an integral type that you can perform these operations on, or seriously rewrite the way your heap works.
To allow a generic-ish heap that fails with a sensible error when supplied a non-integral TYPE, you can do this:
template<class TYPE>
class Heap{
private:
static_assert(std::is_integral<TYPE>::value, "Must be an integral type");
If you actually wanted your heap to work with strings... well. That's another problem altogether. You could try storing a hash of all your values:
#include <functional>
// ...
std::hash<TYPE> hashfunc;
size_t hashval = hashfunc(pos);
Hash functions are defined for all the standard library types, and return a nice integral size_t value that can be fed to the rest of your heap algorithm without any substantial changes, I think. You'd still need to keep a mapping back from hash values to original data if you wanted to return useful values from bubble_up, etc, but I'll leave that as an exercise to the reader.

Related

Stack implementation using Array (ways to improve code)

Need to implement stack using array only, methods: push, pop, print.
The task itself:
Implement stack using only array. The only time compiler should allocate memory is through set_size function.
The current code version works good enough, but I'm looking for ways to improve it's exec-time / complexity / readability etc. Any ideas?
Thank you in advance.
#include <vector>
#include <string>
template <class T>
class Stack
{
int size = 0;
T* Array;
int top = 0;
public:
Stack(size_t Size);
~Stack()
{
delete[] Array;
}
void push(T element);
void pop();
void print();
};
template <class T>
Stack<T>::Stack(size_t Size)
{
size = Size;
top = -1;
Array = new T[size];
}
template <class T>
void Stack<T>::push(T element)
{
if (top >= (size - 1))
{
std::cout << "overflow" << std::endl;
}
else
{
Array[++top] = element;
}
}
template <class T>
void Stack<T>::pop()
{
if (top < 0)
{
std::cout << "underflow" << std::endl;
}
else
{
std::cout << Array[top--] << std::endl;
}
}
template <class T>
void Stack<T>::print()
{
if (top == -1)
{
std::cout << "empty" << std::endl;
}
int i = top;
while (i > -1)
{
std::cout << Array[i--] << " ";
}
std::cout << std::endl;
}
template <class T>
Stack<T> set_size(int Size)
{
return Stack<T>(Size);
}
int main()
{
auto stack = set_size<std::string>(5);
stack.push("hello");
stack.push("hi");
stack.push("hey");
stack.push("greetings");
stack.push("welcome");
stack.print();
stack.pop();
stack.pop();
stack.print();
return 0;
}```
Your main problem comes from the type conversion between your stack pointer top to your stack size size.
top is an int, which is a signed type.
size_t is an unsigned integral type.
When testing (top >= (size - 1)), top is converted to an unsigned int and then considered as UINT_MAX instead of -1, which is always >= to any other unsigned int.
You can either use a size_t as your stack pointer, which means that you cannot use negative value, or convert (size - 1) to a signed value before comparing to top (but this last solution means that you must ensure that the size you specify as a size_t is not too big to be converted to a signed int).
Your print function has also two issues:
in your first test, you assign -1 to top instead of comparing the values
you change your top stack pointer, so that you stack is in an inconsistant state after a call to print()
Your branch predictions are possibly not optimal. You should inspect the resulting assembly to see if the prediction bets on the if rather than on else in your if...else constructs (it will probably predict the if and in this case you should put the common case in the if).
You should pass the arguments by reference and not by value. It doesn't matter in case of simple integers but if your T becomes something more complex, it will result in redundant copy upon push.

Sorting doesn't work with templated class

I have an insertion sort function
void insertionSort(ArrayList<int> myData)
{
for (int i = 1; i < myData.getSize(); i++) {
int index = myData[i];
int j = i;
while (j > 0 && myData[j-1] > index) {
myData.swap(j - 1, j);
j--;
}
myData[j] = index;
}
}
which uses this swap function
template<class TYPE>
void ArrayList<TYPE>::swap(int from, int to) throw(std::out_of_range)
{
int temp = 0;
temp = this->items[from];
this->items[from] = this->items[to];
this->items[to] = temp;
swapNum++;
}
This is how my private methods look like
TYPE * items;
int currentLength;
static int swapNum;
I have an overloaded [] operator and a getSize() function that I think I wrote well and not contributing to my problem. Now if I do this in my main.cpp
ArrayList<int>m_Data(1);
and append say 4,2,9,1 on the m_Data and call
insertionSort(m_Data);
I get two errors
1. Error C2440 '=': cannot convert from 'std::string' to 'int'
on the swap function and
2. The insertion sort doesn't work
First problem: it should be something like TYPE temp = this->items[from]. After repairing it (I used STL swap) function works. Well, it works on STL vector and swap. If you still do have problem, then your array structure is probably invalid.
EDIT: In function 'insertionSort' shouldn't you have template (as in swap function)?

Trouble Using Template Bubblesort with Array of Structs

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

C++ code improvement, array out of bounds

This is a class template for an Array. I overloaded the [ ] operator in hopes it would fix the "out of bounds" issue. The print outs work well, except if it falls out of range, the compiler enables the range by default and it displays a 6 digit number.
Perhaps looking for a better way to initialize the arrays with the appropriate element number for a better check and if it does fall out of range when looking up the element, display an error.
// implement the class myArray that solves the array index
// "out of bounds" problem.
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
template <class T>
class myArray
{
private:
T* array;
int begin;
int end;
int size;
public:
myArray(int);
myArray(int, int);
~myArray() { };
void printResults();
// attempting to overload the [ ] operator to find correct elements.
int operator[] (int position)
{if (position < 0)
return array[position + abs(begin)];
else
return array[position - begin];
}
};
template <class T>
myArray<T>::myArray(int newSize)
{
size = newSize;
end = newSize-1;
begin = 0;
array = new T[size] {0};
}
template <class T>
myArray<T>::myArray(int newBegin, int newEnd)
{
begin = newBegin;
end = newEnd;
size = ((end - begin)+1);
array = new T[size] {0};
}
// used for checking purposes.
template <class T>
void myArray<T>::printResults()
{
cout << "Your Array is " << size << " elements long" << endl;
cout << "It begins at element " << begin << ", and ends at element " << end << endl;
cout << endl;
}
int main()
{
int begin;
int end;
myArray<int> list(5);
myArray<int> myList(2, 13);
myArray<int> yourList(-5, 9);
list.printResults();
myList.printResults();
yourList.printResults();
cout << list[0] << endl;
cout << myList[2] << endl;
cout << yourList[9] << endl;
return 0;
}
First of all, your operator[] is not correct. It is defined to always return int. You will get compile-time error as soon as you instantiate array of something, that is not implicitly convertible to int.
It should rather be:
T& operator[] (int position)
{
//...
}
and, of course:
const T& operator[] (int position) const
{
//you may want to also access arrays declared as const, don't you?
}
Now:
I overloaded the [ ] operator in hopes it would fix the "out of bounds" issue.
You didn't fix anything. You only allowed clients of your array to define custom boundaries, nothing more. Consider:
myArray<int> yourList(-5, 9);
yourList[88] = 0;
Does your code check for out-of-bounds cases like this one? No.
You should do it:
int operator[] (int position)
{
if((position < begin) || (position > end)) //invalid position
throw std::out_of_range("Invalid position!");
//Ok, now safely return desired element
}
Note, that throwing exception is usually the best solution in such case. Quote from std::out_of_range doc:
It is a standard exception that can be thrown by programs. Some components of the standard library, such as vector, deque, string and bitset also throw exceptions of this type to signal arguments out of range.
An better option to redefining an array class is to use the containers from the std library. Vector and array(supported by c++11). They both have an overloaded operator [] so you can access the data. But adding elements using the push_back(for vector) method and using the at method to access them eliminates the chance or getting out of range errors, because the at method performs a check and push_back resizes the vector if needed.

push_back of STL list got bad performance?

I wrote a simple program to test STL list performance against a simple C list-like data structure. It shows bad performance at "push_back()" line. Any comments on it?
$ ./test2
Build the type list : time consumed -> 0.311465
Iterate over all items: time consumed -> 0.00898
Build the simple C List: time consumed -> 0.020275
Iterate over all items: time consumed -> 0.008755
The source code is:
#include <stdexcept>
#include "high_resolution_timer.hpp"
#include <list>
#include <algorithm>
#include <iostream>
#define TESTNUM 1000000
/* The test struct */
struct MyType {
int num;
};
/*
* C++ STL::list Test
*/
typedef struct MyType* mytype_t;
void myfunction(MyType t) {
}
int test_stl_list()
{
std::list<mytype_t> mylist;
util::high_resolution_timer t;
/*
* Build the type list
*/
t.restart();
for(int i = 0; i < TESTNUM; i++) {
mytype_t aItem;
aItem->num = i;
mylist.push_back(aItem);
}
std::cout << " Build the type list : time consumed -> " << t.elapsed() << std::endl;
/*
* Iterate over all item
*/
t.restart();
std::for_each(mylist.begin(), mylist.end(), myfunction);
std::cout << " Iterate over all items: time consumed -> " << t.elapsed() << std::endl;
return 0;
}
/*
* a simple C list
*/
struct MyCList;
struct MyCList{
struct MyType m;
struct MyCList* p_next;
};
int test_simple_c_list()
{
struct MyCList* p_list_head = NULL;
util::high_resolution_timer t;
/*
* Build it
*/
t.restart();
struct MyCList* p_new_item = NULL;
for(int i = 0; i < TESTNUM; i++) {
p_new_item = (struct MyCList*) malloc(sizeof(struct MyCList));
if(p_new_item == NULL) {
printf("ERROR : while malloc\n");
return -1;
}
p_new_item->m.num = i;
p_new_item->p_next = p_list_head;
p_list_head = p_new_item;
}
std::cout << " Build the simple C List: time consumed -> " << t.elapsed() << std::endl;
/*
* Iterate all items
*/
t.restart();
p_new_item = p_list_head;
while(p_new_item->p_next != NULL) {
p_new_item = p_new_item->p_next;
}
std::cout << " Iterate over all items: time consumed -> " << t.elapsed() << std::endl;
return 0;
}
int main(int argc, char** argv)
{
if(test_stl_list() != 0) {
printf("ERROR: error at testcase1\n");
return -1;
}
if(test_simple_c_list() != 0) {
printf("ERROR: error at testcase2\n");
return -1;
}
return 0;
}
Oops, Yes.
I modified the code, and it show:
$ ./test2
Build the type list : time consumed -> 0.163724
Iterate over all items: time consumed -> 0.005427
Build the simple C List: time consumed -> 0.018797
Iterate over all items: time consumed -> 0.004778
So, my question is, why my "push_back" code got bad performance?
Well one thing is that in C, you have a linked list of objects but in C++, you have a linked list of pointers (so for one thing, you are doing twice as many allocations). To compare apples to apples, your STL code should be:
int test_stl_list()
{
std::list<MyType> mylist;
util::high_resolution_timer t;
/*
* Build the type list
*/
t.restart();
for(int i = 0; i < TESTNUM; i++) {
MyItem aItem;
aItem.num = i;
mylist.push_back(aItem);
}
std::cout << " Build the type list : time consumed -> " << t.elapsed() << std::endl;
return 0;
}
Your STL codes create a memory piece twice for each cell.
The following is from STL 4.1.1 on x86_64
void push_back(const value_type& __x)
{
this->_M_insert(end(), __x);
}
// Inserts new element at position given and with value given.
void _M_insert(iterator __position, const value_type& __x)
{
_Node* __tmp = _M_create_node(__x); // Allocate a new space ####
__tmp->hook(__position._M_node);
}
As you can see, also, push_back() function calls several more functions before returning to the caller, and
few pointer-value copying occurs everytime one of the functions is called.
Might be neligible because all the parameters are passed by const-reference though.
First, it looks like you're doing a push_front, not a push_back (in your own implementation, that is).
Second, you should also compare std::slist for a fair comparison as the std::list is double-linked.
Third, you need to use right compiler flags for a fair comparison. With gcc you should at least compile with -O2. Without optimization, STL always sucks because no inlining is done and there is lots of function call overhead.
It would seem your high_resolution_timer class is measuring more than just the routines you are trying to measure. I would refactor the code such that the only code between t.restart() and t.elapsed() is what you are keen on measuring. All other code therein could have unknown performance implications that could skew your results.