I want to sort a vector using std::sort, but my sort method is a static method of a class, and I want to call std::sort outside it, but it seems to be trouble doing it this way.
On the class:
static int CompareIt(void *sol1, void *sol2) { ... }
std::sort call:
sort(distanceList.at(q).begin(),
distanceList.at(q).end(),
&DistanceNodeComparator::CompareIt);
Shouldn't it be possible to do this way?
std::sort takes a comparator that accepts value of the type held in the collection and returns bool. It should generally implement some notion of <. E.g., assuming your distanceList elements have collections of integers (I assume they don't, but for the sake of the example):
static bool CompareIt(int sol1, int sol2) { ... }
And of course you only need to supply a comparator if there isn't already a < operator that does the right thing for your scenario.
It should be a boolean method (sort uses operator <() by default to compare values)
The comparison function you've provided has the signature of the one needed by qsort, which is the sorting function that C provided before C++ came along. sort requires a completely different function.
For example if your declaration of distanceList is std::vector<DistanceNode> your function would look like:
static bool CompareIt(const DistanceNode &sol1, const DistanceNode &sol2)
{
return sol1.key < sol2.key;
}
Notice that sorting a std::list with the standard sort algorithm isn't efficient, which is why list supplies its own sort member function.
As others have mentioned, it needs a boolean return type. Here's an example which works:
#include "stdafx.h"
#include <vector>
#include <algorithm>
using namespace std;
class MyClass
{
public:
static bool CompareIt(const void *a1, const void *a2)
{
return a1 < a2;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
// Create a vector that contains elements of type MyData
vector<void*> myvector;
// Add data to the vector
myvector.push_back((void*)0x00000005);
myvector.push_back((void*)0x00000001);
// Sort the vector
std::sort(myvector.begin(), myvector.end(), MyClass::CompareIt);
// Display some results
for( int i = 0; i < myvector.size(); i++ )
{
printf("%d = 0x%08X\n", i, myvector[i] );
}
return 0;
}
[Edit] Updated the code above to make it a little simpler. I'm not suggesting it's nice code, but without know more about the OPs real implementation, it's difficult to give a better example!
First, the return type should be bool. Actually the requirement is only that the return type be assignable to bool, which int is. But the fact that you're returning int suggests that you might have written a three-way comparator instead of the strict weak ordering required by std::sort.
Your CompareIt function takes two void* pointers as parameters. Is distanceList.at(q) a vector<void*> (or vector of something convertible to void*)? If not, then the comparator inputs aren't right either. Using void* with algorithms also suggests that you're doing something wrong, because much of the point of generic programming is that you don't need opaque pointers that later get cast back to their original type.
Related
So, I had an assignment to write a program to test speeds of different sorting algorithms, and one of them is good old qsort. I need to pass a comparator to it, but not the one it expects, but something boolean a-la std::less, and I know that to use it so that qsort accepts it, I need to actually pass it something like less(b, a) - less(a,b) --- this way, it has the range of [-1; 1] and produces what I need.
The problem is this: I have no idea how to actually do it! I tried to use lambda --- and (because I need to capture the comparator and qsort can't handle this) it failed. I tried to create another function converting my comparator to qsort's:
int make_comparator(const void* a, const void* b) {
return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}
But I have no idea on how to actually pass the comp to it (because i can't just write qsort(..., make_comparator(comp, a, b)), can I?). I tried to use a template to pass comp, but couldn't figure out how.
So I'm struggling with it for like an hour already, and I'm no closer to a solution. What's the correct way to do this?
You can try something like this. qsort_friendly_comparator just acts a wrapper around the comparator object. The only downside is that you have to manually specify the comparator type and its argument type.
#include <functional>
#include <cstdlib>
#include <cstdio>
// Assumes Comparator take two arguments of the same type and returns a bool.
// Have to manually specify the ArgType because it is tricky to deduce without
// excessive template magic.
template <typename Comparator, typename ArgType>
int qsort_friendly_comparator(const void *first, const void *second)
{
Comparator comp;
return (int)comp(*(ArgType*)second, *(ArgType*)first) -
(int)comp(*(ArgType*)first, *(ArgType*)second);
}
int main() {
int data[] = {2, 1, 3, 0};
qsort(data,
/*num_elem=*/4,
/*size_of_elem=*/sizeof(int),
&qsort_friendly_comparator<std::less<int>, int>);
for (int i = 0; i < 4; i++) {
printf("%d ", data[i]);
}
printf("\n");
}
You cannot pass cmp to make_comparator via qsort. Your best option is to have a function pointer that is set to the right function.
bool (*comp)(int a, int b) = nullptr;
int make_comparator(const void* a, const void* b) {
return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}
and later set comp to a valid function pointer
comp = <some function pointer>;
before calling qsort.
qsort(ptr, count, size, make_comparator);
If you choose to follow this approach, make sure to add checks in make_comparator to prevent calling cmp when it is not set to a valid function.
int make_comparator(const void* a, const void* b) {
if ( comp == nullptr )
{
// Deal with error
}
return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}
We're taught to create function objects to use algorithms.
There are algorithms that call the operator(), like:
for_each
find_if
remove_if
max_element
count_if
These function objects should typically inherit from unary_function or binary_function, to behave like a function, a predicate, etc.
But books don't generally demonstrate examples for creating OutputIterators:
e.g. to traverse the output of functions like
std::set_intersection(), I have to provide a destination container,
and then traverse the result:
std::vector<int> tmp_dest;
std::set_difference (
src1.begin(), src1.end(),
src2.begin(), src2.end(),
std::back_inserter(tmp_dest));
std::for_each( tmp_dest.begin(), tmp_dest.end(), do_something );
int res = std::accumulate( tmp_dest.begin(), tmp_dest.end(), 0 );
but think that it would be more efficient sometimes to use the values of each algorithm, without storing them first, like:
std::set_difference (
src1.begin(), src1.end(),
src2.begin(), src2.end(),
do_something );
Accumulator accumulate(0); // inherits from std::insert_iterator ?
std::set_difference (
src1.begin(), src1.end(),
src2.begin(), src2.end(),
accumulate );
Should we generally create classes like this Accumulator ?
What should its design look like?
What should it inherit from ?
Accumulator could inherit from insert_iterator, but it is not really an iterator (eg it does not implement operator++() )
what are the widely accepted practices?
If you want an output iterator that calls your own function for every value received, use Boost.Iterator's function_output_iterator.
I don't see a fundamental problem with this as long as it's clear to future maintainers how the codes works and what it's doing.
I would probably not inherit such an operation from any standard class (Other than giving it output_iterator_tag). Since we're dealing with templates we don't need to have a parent interface to deal with.
But keep in mind that your statement (eg it does not implement operator++() ) doesn't seem to be correct: Whatever you pass in as the "output iterator" needs to meet the requirements of output iterators which include being copyable, dereference-to-assign, and incrementable. Whatever object type you pass in needs to meet these requirements.
My take on this would be using Boost (also showing Boost Range algorithm versions of set_difference, although off-topic):
#include <set>
#include <boost/range/algorithm.hpp>
#include <boost/function_output_iterator.hpp>
#include <cassert>
void do_something(int) {}
int main()
{
const std::set<int>
src1 { 1,2,3 },
src2 { 1,9 };
unsigned total = 0;
boost::set_difference(src1, src2,
boost::make_function_output_iterator([&](int i)
{
total += i*i;
}));
assert(total == 13); // 2*2 + 3*3
}
See it Live On Coliru
The target of algorithms taking an output iterator is a sequence of values represented by an output iterator. They use iterators for two reasons:
It is quite likely that the result is stored somewhere else, i.e., an iterator is useful.
The protocol mandates that each position is written just once. This is more restictive than a function call interface, i.e., there is an additional guarantee.
For some algorithms both versions, one with a function call interface and one with an iterator interface, are provided. For example, that is the difference between std::for_each() and std::copy().
In any case, if all you need is having a function called where an output iterator is needed, just have the other iterator operations be no-ops and call the function upon assignment to the result of *it: this creates a perfectly valud output iterator.
Following works:
#include <cassert>
#include <algorithm>
class AccumulatorIterator
{
public:
explicit AccumulatorIterator(int initial) : value(initial) {}
AccumulatorIterator& operator = (int rhs) { value += rhs; return *this; }
AccumulatorIterator& operator *() { return *this; }
AccumulatorIterator& operator ++() { return *this; }
operator int() const { return value; }
private:
int value;
};
int main() {
int first[] = {5,10,15,20,25};
int second[] = {50,40,30,20,10};
std::sort(std::begin(first), std::end(first)); // 5 10 15 20 25
std::sort(std::begin(second), std::end(second)); // 10 20 30 40 50
const int res = std::set_intersection (std::begin(first), std::end(first),
std::begin(second), std::end(second), AccumulatorIterator(0));
assert(res == 10 + 20);
return 0;
}
char word[100],p[100],result[4][100];
I want to sort the result[4][100] alphabetically. for example
result[0]="adbs";
result[1]="aacs";
result[2]="abef";
result[3]="abbm";
after sort it will be:
result[0]="aacs";
result[1]="abbm";
result[2]="abbm";
result[3]="adbs";
how can I do this using library function or STL. thanks in advance,
What about making result an array of std::string instead and sorting that:
std::string result[4];
std::sort(result, result + (sizeof(result) / sizeof(result[0])));
Mark B's answer is the C++ way to do things.
If you are stuck with the raw character arrays, you might be better off with a C-style approach.
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <iostream>
typedef int (*Comparator)(const void *, const void *);
int main() {
const std::size_t cWords = 4;
char result[cWords][100] = { "az", "ax", "aa", "ab" };
std::qsort(result, cWords, sizeof(result[0]),
reinterpret_cast<Comparator>(std::strcmp));
for (std::size_t i = 0; i < cWords; ++i) {
std::cout << result[i] << std::endl;
}
return 0;
}
The approach is essentially the same, but the details differ.
qsort takes void pointers, the type size, and a comparison function (that also uses void pointers) to implement a sort on any kind of data type.
std::sort uses templates to handle the type-specific details, so you can work at a higher level of abstraction and also get better type-safety. But this can be harder to get right when you don't have a real type but just a fixed-length character array. The std::sort approach can potentially be faster, since the compiler has the chance to inline the comparison function.
What I am trying to do is:
#include <QVector>
#include <QLinkedList>
#include <QSet>
class MyType
{
//...
};
int main(int argc, char** argv)
{
QVector<MyType> vector;
QSet<QVector<MyType>::iterator> a;
a.insert(vector.begin()); // This is fine
QLinkedList<MyType> linkedList;
QSet<QLinkedList<MyType>::iterator> b;
b.insert(linkedList.begin()); // This does not compile
return 0;
}
The compiler message is:
error: no matching function for call to 'qHash(const QLinkedList<MyType>::iterator&)'
I know, that the reason why the first three lines compile is that for the QVector, the iterator is defined as typedef T* iterator; but for the QLinkedList it is a custom type.
I found out, that the QSet template class is implemented in terms of a hash table.
Apparently it is possible to evaluate the hash function for a pointer, but not for a custom type.
Please, could you tell me, how to overload the qHash function for my program to compile? I have read some basic information on the workings of a hash table, but I lack the confidence in the subject.
I tried to understand the inner workings of the QLinkedList<T>::iterator. It seems that it is very similar to the QVector<T>::iterator. It just holds a pointer to a node in the linked list instead of a pointer to the item itself.
class iterator
{
public:
...
Node *i;
...
};
So I tried to define the function in this manner:
uint qHash(QLinkedList<MyType>::iterator it)
{
return qHash(it.i);
}
The program compiled, but I have no confidence in my solution. How should I correctly overload the qHash function?
You did perfectly well already. The basic rules of hash functions are:
If x = y then hash(x) = hash(y).
If x != y then hash(x) != hash(y) (as often as possible). This isn't a strict rule, but the better it's followed, the better the performance of the hash table. Ideally, the outputs will appear random.
Your way works because if two iterators, ia and ib are equal (referring to the same node), their internal pointers, ia.i and ib.i will be equal. That takes care of rule 1. Then you use a built-in hash function on those pointers; Qt takes care of rule 2 for you.
Cheers!
I'm trying to sort a concurrent_vector type, where hits_object is:
struct hits_object{
unsigned long int hash;
int position;
};
Here is the code I'm using:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
Now I have filled up a concurrent_vector<hits_object*> called hits.
But I want to sort this concurrent_vector on position property!!!
Here is an example of what's inside a typical hits object:
0 1106579628979812621
4237 1978650773053442200
512 3993899825106178560
4749 739461489314544830
1024 1629056397321528633
5261 593672691728388007
1536 5320457688954994196
5773 9017584181485751685
2048 4321435111178287982
6285 7119721556722067586
2560 7464213275487369093
6797 5363778283295017380
3072 255404511111217936
7309 5944699400741478979
3584 1069999863423687408
7821 3050974832468442286
4096 5230358938835592022
8333 5235649807131532071
I want to sort this based on the first column ("position" of type int). The second column is "hash" of type unsigned long int.
Now I've tried to do the following:
std::sort(hits.begin(),hits.end(),compareByPosition);
where compareByPosition is defined as:
int compareByPosition(const void *elem1,const void *elem2 )
{
return ((hits_object*)elem1)->position > ((hits_object*)elem2)->position? 1 : -1;
}
but I keep getting segmentation faults when I put in the line std::sort(hits.begin(),hits.end(),compareByPosition);
Please help!
Your compare function needs to return a boolean 0 or 1, not an integer 1 or -1, and it should have a strongly-typed signature:
bool compareByPosition(const hits_object *elem1, const hits_object *elem2 )
{
return elem1->position < elem2->position;
}
The error you were seeing are due to std::sort interpreting everything non-zero returned from the comp function as true, meaning that the left-hand side is less than the right-hand side.
NOTE : This answer has been heavily edited as the result of conversations with sbi and Mike Seymour.
int (*)(void*, void*) is the comparator for C qsort() function. In C++ std::sort() the prototype to the comparator is:
bool cmp(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
std::sort(hits.begin(), hits.end(), &cmp);
On the other hand, you can use std::pair struct, which by default compares its first fields:
typedef std::pair<int position, unsigned long int hash> hits_object;
// ...
std::sort(hits.begin(), hits.end());
Without knowing what concurrent_vector is, I can't be sure what's causing the segmentation fault. Assuming it's similar to std::vector, you need to populate it with hits.push_back(obj) rather than hits[i] = j; you cannot use [] to access elements beyond the end of a vector, or to access an empty vector at all.
The comparison function should be equivalent to a < b, returning a boolean value; it's not a C-style comparison function returning negative, positive, or zero. Also, since sort is a template, there's no need for C-style void * arguments; everything is strongly typed:
bool compareByPosition(hits_object const * elem1, hits_object const * elem2) {
return elem1->position < elem2->position;
}
Also, you usually don't want to use new (and certainly never malloc) to create objects to store in a vector; the simplest and safest container would be vector<hits_object> (and a comparator that takes references, rather than pointers, as arguments). If you really must store pointers (because the objects are expensive to copy and not movable, or because you need polymorphism - neither of which apply to your example), either use smart pointers such as std::unique_ptr, or make sure you delete them once you're done with them.
The third argument you pass to std::sort() must have a signature similar to, and the semantics of, operator<():
bool is_smaller_position(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
When you store pointers in a vector, you cannot overload operator<(), because smaller-than is fixed for all built-in types.
On a sidenote: Do not use malloc() in C++, use new instead. Also, I wonder why you are not using objects, rather than pointers. Finally, if concurrent_vector is anything like std::vector, you need to explicitly make it expand to accommodate new objects. This is what your code would then look like:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object obj;
obj.position=i;
obj.hash=_prevHash[tid];
hits.push_back(obj);
}
This doesn't look right:
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
here you already are sorting the array based on 'i' because you set position to i as well as it becomes the index of hits!
also why using malloc, you should use new(/delete) instead. You could then create a simple constructor for the structure to initialize the hits_object
e.g.
struct hits_object
{
int position;
unsigned int hash;
hits_object( int p, unsigned int h ) : position(p), hash(h) {;}
};
then later write instead
hits_object* obj = new hits_object( i, _prevHash[tid] );
or even
hits.push_back( new hits_object( i, _prevHash[tid] ) );
Finally, your compare function should use the same data type as vector for its arguments
bool cmp( hits_object* p1, hits_object* p2 )
{
return p1->position < p2->position;
}
You can add a Lambda instead of a function to std::sort.
struct test
{
int x;
};
std::vector<test> tests;
std::sort(tests.begin(), tests.end(),
[](const test* a, const test* b)
{
return a->x < b->x;
});