Before I get my fair share of "this is a duplicate of link-to-thread" replies, I'd like to say that I've implemented both what I have been reading on StackOverflow and on the CPlusPlus website. The problem is that my vector won't sort. I must be missing something in the implementation. Maybe incorrect use of references etc.
Here goes: I have two classes - DETargetParam and a wrapper class named DETargetParamVector that includes an STL vector of type DETargetParam. My objective is to sort the std::vector in ascending order using the fitness member variable of DETargetParam. I've tried to do that by overloading the less than operator in the DETargetParam class and returning a boolean result.
This, however, does not sort. Everything compiles and executes perfectly, but there's no sort. I really hope someone here can help me.
This is the source code for DETargetParam:
#ifndef _DE_TARGET_PARAM_H_DP_
#define _DE_TARGET_PARAM_H_DP_
template <typename T, unsigned int N>
class DETargetParam {
private:
/** The array of N parameters in type T */
T param[N];
long double fitness;
long double probability;
long double probabilityInterval;
public:
/**
* #brief Default constructor.
*
* Nada!
*/
DETargetParam() {
/* NULL */
}
long double getFitness() {
return fitness;
}
void setFitness(long double x) {
fitness = x;
}
long double getProbability() {
return probability;
}
void setProbability(long double x) {
probability = x;
}
long double getProbabilityInterval() {
return probabilityInterval;
}
void setProbabilityInterval(long double x) {
probabilityInterval = x;
}
bool operator<(const DETargetParam& rhs) const {
return (fitness < rhs.fitness);
}
T& operator[](unsigned int i) {
return param[i];
}
};
#endif // _DE_TARGET_PARAM_H_DP_
and the DETargetParamVector wrapper class:
#ifndef _DE_TARGET_PARAM_VECTOR_H_DP_
#define _DE_TARGET_PARAM_VECTOR_H_DP_
#include <algorithm>
#include <cstdio>
#include <vector>
#include "DETargetParam.h"
template <typename T, unsigned int N, unsigned int NP>
class DETargetParamVector {
private:
/** This is a STL vector holding the parameters */
std::vector< DETargetParam<T, N> > vec;
public:
/**
* #brief Default constructor
*
* Move along... nothing to see here.
*/
DETargetParamVector() {
vec.reserve(NP);
}
void SortAndCalculate() {
SortVector();
PrintSorted();
}
void SortVector() {
std::sort(vec.begin(), vec.end());
}
void PrintSorted() {
for (unsigned int i = 0; i < NP; ++i) {
fprintf(stdout, "%.12Lf, %.12Lf, %.12Lf\n", vec[i].getFitness(), vec[i].getProbability(), vec[i].getProbabilityInterval());
}
fprintf(stdout, "\n");
fflush(stdout);
}
DETargetParam<T, N>& operator[](unsigned int i) {
return vec[i];
}
};
#endif // _DE_TARGET_PARAM_VECTOR_H_DP_
and the main function details:
#include <cmath>
#include <ctime>
#include "DETargetParamVector.h"
const unsigned int N = 10;
const unsigned int NP = 10;
int main() {
srand(time(0));
DETargetParamVector<long double, N, NP> targetVector;
// For each member of the population.
for (unsigned int i = 0; i < NP; ++i) {
targetVector[i].setFitness(static_cast<long double>(rand()));
}
targetVector.SortAndCalculate();
return 0;
}
Thanks in advance.
Your vector does get sorted. The issue is that your vector is empty, and all you do is write and read outside of the vector.
/**
* #brief Default constructor
*
* Move along... nothing to see here.
*/
DETargetParamVector() {
vec.reserve(NP);
}
The comment is quite ironic, because here is your error. vec.reserve(NP) does not change the size of the vector, it just does something to save work in the future. You need to replace reserve with resize, or even better just initialize it from the start:
/**
* #brief Default constructor
*
* Move along... nothing to see here.
*/
DETargetParamVector() : vec(NP) {
}
On a side node, this:
int N = 10;
int NP = 10 * N;
int main() {
DETargetParamVector<long double, N, NP> targetVector;
is illegal, because you have non-const ints as template arguments. You need to replace int N with int const N (likewise for NP).
I've put together a somewhat simplified version of your code, that at least works to generate and sort some objects. I've also (at least IMO) fixed a few places that your design struck me as somewhat problematic (though the result still falls well short of perfect, at least IMO).
de_target_param.h:
#ifndef _DE_TARGET_PARAM_H_DP_
#define _DE_TARGET_PARAM_H_DP_
#include <iostream>
template <typename T, unsigned int N>
class DETargetParam {
private:
/** The array of N parameters in type T */
// T param[N];
long double fitness;
// long double probability;
// long double probabilityInterval;
public:
DETargetParam(long double f) : fitness(f) { }
/*
long double getFitness() {
return fitness;
}
void setFitness(long double x) {
fitness = x;
}
long double getProbability() {
return probability;
}
void setProbability(long double x) {
probability = x;
}
long double getProbabilityInterval() {
return probabilityInterval;
}
void setProbabilityInterval(long double x) {
probabilityInterval = x;
}
*/
friend std::ostream &operator<<(std::ostream &os, DETargetParam const &d) {
return os << d.fitness;
}
bool operator<(const DETargetParam& rhs) const {
return (fitness < rhs.fitness);
}
};
#endif // _DE_TARGET_PARAM_H_DP_
de_target_param_vector.h:
#include "de_target_param.h"
#ifndef _DE_TARGET_PARAM_VECTOR_H_DP_
#define _DE_TARGET_PARAM_VECTOR_H_DP_
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
template <typename T, unsigned int N, unsigned int NP>
class DETargetParamVector {
std::vector< DETargetParam<T, N> > vec;
public:
void push(DETargetParam<T, N> const &d) {
vec.push_back(d);
}
void SortAndCalculate() {
SortVector();
std::cout << *this;
}
void SortVector() {
std::sort(vec.begin(), vec.end());
}
friend std::ostream &operator<<(std::ostream &os, DETargetParamVector const &d) {
std::copy(d.vec.begin(), d.vec.end(), std::ostream_iterator<DETargetParam<T, N> >(os, "\n"));
return os;
}
};
#endif // _DE_TARGET_PARAM_VECTOR_H_DP_
And, I've written a small main that creates, sorts, and prints, (in sorted order) some objects:
#include "de_target_param_vector.h"
int main() {
DETargetParamVector<int, 1, 5> params;
for (int i=0; i<5; i++)
params.push(rand());
params.SortAndCalculate();
return 0;
}
Based on how you designed your DETargetParam class, I think a bit of Googling for "pseudo object oriented" or something similar should turn up some useful, relevant reading. A great deal of your code seems (at least to me) to exemplify the genre.
Related
I have a question about passing the comparison function to sort().
What I want to do is define a sort() function that takes into account for its calculation a member variable of the class that I want to do the sorting in.
Basically, my code looks like this (simplified to only show the relevant parts):
MappingTechnique.h
struct MappingTechnique {
vector<int> usedIndexCount;
};
struct SimpleGreedyMappingTechnique : MappingTechnique {
bool sortByWeights(int index1, int index2);
};
MappingTechnique.m
bool SimpleGreedyMappingTechnique::sortByWeights(int index1, int index2) {
return usedIndexCount[index1] > usedIndexCount[index2];
}
void SimpleGreedyMappingTechnique::processFrame(Frame frame) {
vector<int> payloadIndices = <generate the vector>
// sort the payload indices according to their current usedIndexCount
sort(payloadIndices.begin(), payloadIndices.end(), sortByWeights);
}
This code doesn't compile, it gives the following error:
error: reference to non-static member function must be called
and points to sortByWeights.
Is it even possible to use a member function of a class for sorting? If it is, how I can implement this?
It is, but in general I would encourage just using a proper functor or a lambda:
Using a lambda:
std::sort(payloadIndices.begin(), payloadIndices.end(), [this](int a, int b){
return this->sortByWeights(a, b);
});
Alternatively using std::mem_fn:
auto sorter = std::bind(std::mem_fn(SimpleGreedyMappingTechnique::sortByWeights), this);
std::sort(payloadIndices.begin(), payloadIndices.end(), sorter);
Alternatively using a functor:
namespace{
struct indicies_less_than
{
const SimpleGreedyMappingTechnique & mapping_tech;
indicies_less_than(const SimpleGreedyMappingTechnique & mapping_tech)
:mapping_tech(mapping_tech){}
bool operator()(int a, int b)
{
return mapping_tech.sortByWeights(a, b);
}
};
}
std::sort(payloadIndices.begin(), payloadIndices.end(), indicies_less_than(*this));
Note:
if the types being sorted were anything more complicated than an int you would definitely want to pass them by const& to prevent copying
As mentioned by Mgetz, a functor can be used. Example of functor:
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <vector>
#define asize 16
class example{
public:
unsigned int a[asize]; // array
std::vector<size_t> v; // indices to array
example(void)
{
v.resize(asize);
for(size_t i = 0; i < asize; i++){
a[i] = rand()%10;
v[i] = i;
}
}
void displayarray(void)
{
for(size_t i = 0; i < asize; i++)
std::cout << std::setw(3) << a[v[i]];
std::cout << std::endl;
}
class lessthan // lessthan functor for std::sort
{
public:
const example &x;
lessthan(const example &e ) : x(e) { }
bool operator()(const size_t & i0, const size_t & i1)
{
return x.a[i0] < x.a[i1];
}
};
void sortarray(void)
{
std::sort(v.begin(), v.end(), lessthan(*this));
}
};
int main()
{
example x;
x.displayarray();
x.sortarray();
x.displayarray();
return 0;
}
class MyStrValArray
{
private:
vector<char> p;
public:
void init(const int n);
void clear();
unsigned capacity();
unsigned size();
};
I want to have a vector as private class member, and in the public part, I want to declare the size(const int n) of the vector. Is there a way to do this?
And the reason I want to use vector is, I need to get the size / capacity of the memory, resize, or remove the nth element of the memory. Is it right to use vector in this case?
If you are trying to implement custom string implementation then ,having "char * data" is more appropriate.
Otherwise you can use vector like this :
#include <iostream>
#include <vector>
using namespace std;
class MyStrValArray
{
private:
vector<char> p;
public:
MyStrValArray() {}
MyStrValArray(const int sz ) : p(sz){}
void init(const int n)
{
p.resize(n);
}
void clear()
{
p.clear();
}
unsigned capacity()
{
return p.capacity();
}
unsigned size()
{
return p.size();
}
};
int main()
{
MyStrValArray ma;
ma.init(4);
std::cout<<ma.size()<<std::endl;
return 0;
}
So I'm using the STL priority_queue<> with pointers... I don't want to use value types because it will be incredibly wasteful to create a bunch of new objects just for use in the priority queue. So... I'm trying to do this:
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
private:
int m_val;
}
priority_queue<Int*> myQ;
myQ.push(new Int(5));
myQ.push(new Int(6));
myQ.push(new Int(3));
Now how can I write a comparison function to get those to be ordered correctly in the Q? Or, can someone suggest an alternate strategy? I really need the priority_queue interface and would like to not use copy constructors (because of massive amounts of data). Thanks
EDIT: Int is just a placeholder/example... I know I can just use int in C/C++ lol...
You can explicitly specify which comparator your queue should use.
#include <iostream>
#include <sstream>
#include <functional>
#include <vector>
#include <queue>
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
bool operator<(const Int &other) const { return m_val < other.m_val; }
private:
int m_val;
};
template<typename Type, typename Compare = std::less<Type> >
struct pless : public std::binary_function<Type *, Type *, bool> {
bool operator()(const Type *x, const Type *y) const
{ return Compare()(*x, *y); }
};
int main(int argc, char *argv[]) {
std::priority_queue<Int*, std::vector<Int*>, pless<Int> > myQ;
for (int i = 1; i < argc; i++) {
std::stringstream ss(argv[i]);
int x;
ss >> x;
myQ.push(new Int(x));
}
for (; !myQ.empty(); delete myQ.top(), myQ.pop())
std::cout << myQ.top()->getVal() << std::endl;
return 0;
}
One option that will surely work is to replace Int* with shared_ptr<Int> and then implement operator< for shared_ptr<Int>
bool operator<(const shared_ptr<Int> a, const shared_ptr<Int> b)
{
return a->getVal() < b->getVal();
}
An integer is the same size as a pointer on 32 bit systems. On 64 bit systems, a pointer will be twice as big. Therefore, it is simpler/faster/better to use regular integers.
I have a question about passing the comparison function to sort().
What I want to do is define a sort() function that takes into account for its calculation a member variable of the class that I want to do the sorting in.
Basically, my code looks like this (simplified to only show the relevant parts):
MappingTechnique.h
struct MappingTechnique {
vector<int> usedIndexCount;
};
struct SimpleGreedyMappingTechnique : MappingTechnique {
bool sortByWeights(int index1, int index2);
};
MappingTechnique.m
bool SimpleGreedyMappingTechnique::sortByWeights(int index1, int index2) {
return usedIndexCount[index1] > usedIndexCount[index2];
}
void SimpleGreedyMappingTechnique::processFrame(Frame frame) {
vector<int> payloadIndices = <generate the vector>
// sort the payload indices according to their current usedIndexCount
sort(payloadIndices.begin(), payloadIndices.end(), sortByWeights);
}
This code doesn't compile, it gives the following error:
error: reference to non-static member function must be called
and points to sortByWeights.
Is it even possible to use a member function of a class for sorting? If it is, how I can implement this?
It is, but in general I would encourage just using a proper functor or a lambda:
Using a lambda:
std::sort(payloadIndices.begin(), payloadIndices.end(), [this](int a, int b){
return this->sortByWeights(a, b);
});
Alternatively using std::mem_fn:
auto sorter = std::bind(std::mem_fn(SimpleGreedyMappingTechnique::sortByWeights), this);
std::sort(payloadIndices.begin(), payloadIndices.end(), sorter);
Alternatively using a functor:
namespace{
struct indicies_less_than
{
const SimpleGreedyMappingTechnique & mapping_tech;
indicies_less_than(const SimpleGreedyMappingTechnique & mapping_tech)
:mapping_tech(mapping_tech){}
bool operator()(int a, int b)
{
return mapping_tech.sortByWeights(a, b);
}
};
}
std::sort(payloadIndices.begin(), payloadIndices.end(), indicies_less_than(*this));
Note:
if the types being sorted were anything more complicated than an int you would definitely want to pass them by const& to prevent copying
As mentioned by Mgetz, a functor can be used. Example of functor:
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <vector>
#define asize 16
class example{
public:
unsigned int a[asize]; // array
std::vector<size_t> v; // indices to array
example(void)
{
v.resize(asize);
for(size_t i = 0; i < asize; i++){
a[i] = rand()%10;
v[i] = i;
}
}
void displayarray(void)
{
for(size_t i = 0; i < asize; i++)
std::cout << std::setw(3) << a[v[i]];
std::cout << std::endl;
}
class lessthan // lessthan functor for std::sort
{
public:
const example &x;
lessthan(const example &e ) : x(e) { }
bool operator()(const size_t & i0, const size_t & i1)
{
return x.a[i0] < x.a[i1];
}
};
void sortarray(void)
{
std::sort(v.begin(), v.end(), lessthan(*this));
}
};
int main()
{
example x;
x.displayarray();
x.sortarray();
x.displayarray();
return 0;
}
So I'm using the STL priority_queue<> with pointers... I don't want to use value types because it will be incredibly wasteful to create a bunch of new objects just for use in the priority queue. So... I'm trying to do this:
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
private:
int m_val;
}
priority_queue<Int*> myQ;
myQ.push(new Int(5));
myQ.push(new Int(6));
myQ.push(new Int(3));
Now how can I write a comparison function to get those to be ordered correctly in the Q? Or, can someone suggest an alternate strategy? I really need the priority_queue interface and would like to not use copy constructors (because of massive amounts of data). Thanks
EDIT: Int is just a placeholder/example... I know I can just use int in C/C++ lol...
You can explicitly specify which comparator your queue should use.
#include <iostream>
#include <sstream>
#include <functional>
#include <vector>
#include <queue>
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
bool operator<(const Int &other) const { return m_val < other.m_val; }
private:
int m_val;
};
template<typename Type, typename Compare = std::less<Type> >
struct pless : public std::binary_function<Type *, Type *, bool> {
bool operator()(const Type *x, const Type *y) const
{ return Compare()(*x, *y); }
};
int main(int argc, char *argv[]) {
std::priority_queue<Int*, std::vector<Int*>, pless<Int> > myQ;
for (int i = 1; i < argc; i++) {
std::stringstream ss(argv[i]);
int x;
ss >> x;
myQ.push(new Int(x));
}
for (; !myQ.empty(); delete myQ.top(), myQ.pop())
std::cout << myQ.top()->getVal() << std::endl;
return 0;
}
One option that will surely work is to replace Int* with shared_ptr<Int> and then implement operator< for shared_ptr<Int>
bool operator<(const shared_ptr<Int> a, const shared_ptr<Int> b)
{
return a->getVal() < b->getVal();
}
An integer is the same size as a pointer on 32 bit systems. On 64 bit systems, a pointer will be twice as big. Therefore, it is simpler/faster/better to use regular integers.