Is there a portable, minimal-overhead way to count the number of swap operations performed during a std::sort in C++? I would like to do this because I need to compute the sign of the permutation used to sort the list, and I was wondering if there was a way to reuse std::sort for this rather than writing my own sorting function.
I tried to answer real quick by making a wrapper/ custom type to overload std::swap...and then ran into the fact that for super small vectors swap isn't called...following the link in the comments
so attempt 2 added a counter for the move_constructor.
I can't say this is a minimal overhead solution and you're probably better off writing your own sorting function if you need the exact number of swap operations.
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
struct A{
static int swap_count;
static int move_constructor_count;
int a;
A(int _a): a(_a) {}
bool operator<(const A& other) const{
return this->a < other.a;
}
A(const A&other): a(other.a) {move_constructor_count++;}
};
int A::swap_count = 0;
int A::move_constructor_count = 0;
namespace std{
template<>
void swap(A& lhs, A& rhs) {
A::swap_count++;
std::swap(lhs.a, rhs.a);
}
}
int main() {
std::default_random_engine gen;
std::uniform_int_distribution<int> dis(1,100);
std::vector<A> test;
for(int _=0;_<10;_++) test.emplace_back(dis(gen)); //fill a vector randomly
A::move_constructor_count = 0; // emplace calls move constructor
std::sort(test.begin(), test.end());
std::cout << "after sort1: swap count:" << A::swap_count << " move count: " << A::move_constructor_count << std::endl;
// arbitrary way to fill a large test vector
std::vector<A> test2;
for(int _=0;_<1000;_++) test2.emplace_back(dis(gen)); //fill a vector randomly
A::move_constructor_count = 0;
A::swap_count = 0;
std::sort(test2.begin(), test2.end());
std::cout << "after sort2: swap count:" << A::swap_count << " move count: " << A::move_constructor_count << std::endl;
}
gave me
after sort1: swap count:0 move count: 9
after sort2: swap count:1806 move count: 999
Related
I have been trying to make an unordered_set of structs in c++ but it seems to give me this error-
error: call to implicitly-deleted default constructor
of 'std::__1::hash<coor>'
__compressed_pair_elem(__default_init_tag) {}
I included a == operator, can assist me in making a unordered_set of structures?
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>
using namespace std;
struct coor{
int x,y;
bool operator==(coor a) const{
if(a.x == x && a.y == y){
return true;
}
else return false;
};
};
int main(){
unordered_set<coor> myset;
}
std::unordered_set uses hashes to identify objects uniquely. It computes the hash using std::hash<> structure. This is fine for primitive or STL containers as they have defined a hash structure for them. But for your case, there isn't a hash structure to generate the hash. The error says it: std::__1::hash<coor>.
To resolve this, we need to implement a std::hash<> for coor.
namespace std {
template<>
struct hash<coor> {
const size_t operator()(const coor& c) const
{
return std::hash<int>()(c.x) ^ std::hash<int>()(c.y);
}
};
}
Now the std::unordered_set has the required hash structure to compute the hash.
Many people use the solution given in the cppreference. Please see here.
But they always open the std namespace and specialize the template for std::hash
Basically that is not necessary.
According to the definition of the std::unordered_set as defined here, we need a hash function and an equal function. And for the hash function we just need an operator().
So, we can make this easily as a part of our struct. We need to overide the ()-operator and implement the hash function. And then we need to override the ==-operator to get the equal function.
Then we add the our struct name as an additional template parameter.
In my humble opinion, it is better to encapsulate the hash and equal functions in our struct, because only this datatype should know, how to calculate values.
Please see here:
#include <unordered_set>
#include <vector>
#include <iostream>
struct coor {
int x{}, y{};
// Hash function
size_t operator()(const coor& c) const { return std::hash<int>()(c.x) ^ std::hash<int>()(c.y); }
// Equal Function
bool operator==(const coor& other) const { return (x == other.x && y == other.y); }
};
int main() {
// Some test values
std::vector<coor> test{ {1,2}, {3,4}, {5,6}, {1,2} };
// Define the unordered set anf fill it with test value
std::unordered_set<coor, coor> myset(test.begin(), test.end());
// Show result. There is no double value 1,2
for (const coor& c : myset) std::cout << c.x << ' ' << c.y << '\n';
return 0;
}
Of course you may also Lambdas as "free" functions for the hash and the equal.
In the following example, we will define 2 Lambdas, one for calculating the hash and one calculating the equal function.
Since the type of the Lambda is only known to the compiler, we use decltype in the template parameter, to inform the compiler, which function "type" we will use in the template.
As an example I defined variable definitions using all 5 available constructors. Please see here for the description.
Please note: You can always and everywhere delete the "myEqual" function, if you add the operator== to the struct as shown above.
Please see the next example below:
#include <unordered_set>
#include <vector>
#include <iostream>
struct coor {
int x{}, y{};
};
constexpr size_t BucketCount = 20u;
int main() {
// Hash function
auto myHash = [](const coor& c) { return std::hash<int>()(c.x) ^ std::hash<int>()(c.y); };
// Equal function
auto myEqual = [](const coor& c1, const coor& c2) { return c1.x == c2.x && c1.y == c2.y; };
// Constructor Number 1
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset1(BucketCount, myHash, myEqual);
myset1.insert({ 1,2 }); myset1.insert({ 3,4 }); myset1.insert({ 5,6 }); myset1.insert({ 1,2 });
// Constructor Number 2
std::vector<coor> test{ {1,2}, {3,4}, {5,6}, {1,2} };// Some test values
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset2(test.begin(),test.end(), BucketCount, myHash, myEqual);
// Constructor Number 3
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset3(myset2);
// Constructor Number 4
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> mysetTemp(myset2);
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset4(std::move(mysetTemp));
// Constructor Number 5
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset5({ {1,2}, {3,4}, {5,6}, {1,2} }, BucketCount, myHash, myEqual);
// Show result. There is no double value 1,2
for (const coor& c : myset1) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset2) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset3) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset4) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset5) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
return 0;
}
Developed compiled and tested with Microsoft Visual Studio Community 2019, Version 16.8.2
Additionally compiled and tested with gcc10 amnd clang 11
Language: C++17
If you have any questions to the above, then I am happy to answer
I would like to implement something like DoubleVector.
In this class I would also like to implement sort method, which sort v1_ and according to changes in v1_ the order in v2_ will also change.
The code is below:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class DoubleVector
{
vector<int> v1_;
vector<char> v2_;
public:
void sort()
{
//sort v1_ and also change order in v2_ according to changes in v1_
std::sort(v1_.begin(), v1_.end() /*, lambda ?*/);
}
void add(int value_v1, char value_v2)
{
v1_.push_back(value_v1);
v2_.push_back(value_v2);
}
void print()
{
const auto size = v1_.size();
for (size_t i=0;i<size;++i)
{
cout << v1_[i] << " " << v2_[i] << endl;
}
}
};
int main()
{
DoubleVector dv;
dv.add(6, 'g');
dv.add(2, 'r');
dv.add(3, 'y');
dv.add(4, 'a');
cout << "Before sort:" << endl;
dv.print();
dv.sort();
cout << "After sort:" << endl;
dv.print();//the values in v2_ are in the same order they don't change order according to v1_ changes
return 0;
}
As you can see DoubleVector before sort contains:
6 g
2 r
3 y
4 a
And after sort contains:
2 g
3 r
4 y
6 a
I would like to get:
2 r
3 y
4 a
6 g
So the first vector v1_ has been sorted, but the second still has got the same order and I would like to change order of elements in second v2_ vector according to changes in v1_.
I can write it, but I would like to do it in a fast and clean way, maybe using lambda as third argument in std::sort function? Vectors v1_ and v2_ in class DoubleVector must stay as they are.
Thank you very much.
Make a vector of std::pair<int,char> instead. Since operator < on the pair compares first and decides ties on the second, sorting std::vector<std::pair<int,char>> will produce the exact effect that you want:
vector<pair<int,char>> v;
v.push_back(make_pair(6, 'g'));
v.push_back(make_pair(2, 'r'));
v.push_back(make_pair(3, 'y'));
v.push_back(make_pair(4, 'a'));
sort(v.begin(), v.end());
for (int i = 0 ; i != v.size() ; i++) {
cout << v[i].first << " " << v[i].second << endl;
}
Demo.
You can do something like this:-
vector< pair<int,char> >v;
//do what you want
sort(v.begin(),v.end())
The sort function by default sorts according to first value but you can always define according to which criteria should the sort work
C++ STL - How does the third argument of the STL sort() work?
Try the following.
The way it works is to sort the position key pair based on the int vector value only and then use this ordering to extract values.
#include <iostream>
#include <algorithm>
#include <vector>
class dv
{
std::vector<int> _v1;
std::vector<char> _v2;
std::vector<std::pair<int, int> > _order;
public:
inline bool operator() (const std::pair<int, int>& v1_index_1,
const std::pair<int, int>& v1_index_2) const {
return _v1[v1_index_1.first] < _v1[v1_index_2.first];
}
void sort() {
std::sort(_order.begin(), _order.end(), *this);
}
void add(int value_v1, char value_v2) {
_order.push_back(std::pair<int, int>(_v1.size(), _v2.size()));
_v1.push_back(value_v1);
_v2.push_back(value_v2);
}
void print() {
const auto size(_v1.size());
for (size_t i=0; i<size; ++i) {
std::cout << _v1[_order[i].first]
<< " "
<< _v2[_order[i].second]
<< std::endl;
}
}
};
int main() {
dv dv;
dv.add(6, 'g');
dv.add(2, 'r');
dv.add(3, 'y');
dv.add(4, 'a');
std::cout << "before sort: " << std::endl;
dv.print();
std::cout << "sorting: " << std::endl;
dv.sort();
std::cout << "after sort: " << std::endl;
dv.print();
return 0;
}
As the subject says, why does the below code compare some of the elements to themselves?
#include <iostream>
#include <vector>
#include <algorithm>
class a {
public:
a(int value): value(value) {}
~a() {}
bool operator<(const a& rhs) const {
if(this->value == rhs.value)
std::cout << this << " " << this->value << "\t"
<< &rhs << " " << rhs.value << std::endl;
if(this->value < rhs.value)
return true;
return false;
}
int value;
};
int main(int argc, char* argv[]) {
std::vector<a> vec;
for(int i = 0; i < 17; i++)
vec.push_back(a(i));
std::sort(vec.begin(), vec.end());
return 0;
}
I tried the above code on Windows, Linux and OpenBSD, it seems on Windows it doesn't compare the element to itself, but both on Linux and OpenBSD it does. My guess is that it's because of different libraries being used.
On Linux I get output similar to this:
0x96be0d0 8 0xbfc2945c 8
0xbfc2945c 8 0x96be0d0 8
If std::sort is implemented as Quick sort, there is the case, that you compare the current element to the pivot element. I don't have my Sedgewick Algorithms at hand, but I think avoiding this comparison does not speed the algorithm up (or the comparison does no harm to the algorithms complexity). I can look the exact quote up, if you like.
I am starting a c++ class having never done anything in the language before, and I'm pretty confused by vectors.I made a toy example and I don't quite understand why the doubles that I put into a vector become vector's. Here is the code:
#include <iostream>
#include <vector>
using namespace std;
vector<double> a;
void func(vector<double> *);
int main()
{
for (int i = 0; i < 100; i++)
{
a.push_back(double(i));
}
func(&a);
return 0;
}
void func(vector<double> *vec)
{
cout << double(vec[0]) << endl;
return;
}
It ends up giving me this error:
error: cannot convert 'vector' to 'double' without
a conversion operator
and I have no idea what that means. What exactly is happening here and how can I cast a vector into a double?
You don't need to mix using pointers * with std::vector.
Method 1 (not recommended):
Change
cout << double(vec[0]) << endl;
to
cout << double((*vec).at(0)) << endl;
Method 2:
Change
void func(vector<double> *vec)
to
void func(vector<double> vec)
or
void func(const vector<double> &vec)
Change
func(&a);
to
func(a);
The reason for the actual error is more due to a misunderstanding of pointers than vectors . The problem is that you are passing a pointer to a vector. If you want to use the vector itself, then you would do:
cout << (*vec)[0] << endl;
* will dereference the pointer to get the actual vector instance rather than an index into an address which is what you were doing before.
But, as pointed out in the other answer, it is safer just to pass the vector by reference (or better yet, const reference):
void func(const vector<double>& vec)
{
cout << vec[0] << endl;
return;
}
then call as:
func(a);
Another way to use vectors is with a std::vector< TYPE >::const_iterator like this;
#include <iostream>
#include <vector>
double func(std::vector<double>::const_iterator iter);
int main()
{
std::vector<double> vec;
for (double i = 0.0; i < 1; i += 0.1){
vec.push_back(i);
}
std::cout<< func(vec.begin()+3) << " "
<< func(vec.begin()+6) << std::endl;
return 0;
}
double func(std::vector<double>::const_iterator iter){
return *iter;
}
outputs;
0.3 0.6
Question is about sorting std::vector<myclass> using function sort from STL's algorithms class.
Standard way is : sort(v.begin(), v.end(), &myfunct)
where myfunct is:
bool myfunct( myclass first, myclass second ) {
if (first.value < second.value)
return true;
else return false;
}
Approach above takes more than one line. I am curious how to do it in one line. Is it possible define function that compares myclass objects inside sort function? May be somehow use this (a < b) ? a : b. I remember that there is something like this in C#, but I forgot how is it called. Is it possible to do in C++.
First, you can just return first.value < second.value but this doesn't get rid of the function. In C++2011 you can use a lambda function:
std::sort(begin, end, [](myclass const& f, myclass const& s){ return f.value < s.value; });
Without C++2011 I think you'll need a function object because there isn't anything which projects your class to the value you actually want to compare.
BTW, you definitely want to pass everything but the most trivial objects by reference to your comparison function.
You could use boost::lambda and boost::lambda::bind (with boost lambda placeholders)
std::sort(vec.begin(), vec.end(),
boost::lambda::bind(&A::a, boost::lambda::_1)
<
boost::lambda::bind(&A::a, boost::lambda::_2));
sort passes 2 values to the comparison function so you need to compare those 2 values. The bind part of code just selects variable a from the struct A from each structures being compared (referenced by _1 and _2).
Example code:
#include <iostream>
#include <algorithm>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/array.hpp>
struct A
{
A() : a(0), b(0) {}
int a;
int b;
};
std::ostream & operator<<(std::ostream & os, A & a)
{ return os << a.a << ":" << a.b; }
int main()
{
boost::array<A,5> vec;
std::fill(vec.begin(),vec.end(),A());
vec[0].a = 1;
vec[1].a = 3;
vec[2].a = 4;
vec[3].a = 0;
vec[4].a = 2;
std::for_each(vec.begin(),vec.end(), std::cout << boost::lambda::_1 << ' ');
std::cout << std::endl;
std::sort(vec.begin(), vec.end(),
boost::lambda::bind(&A::a, boost::lambda::_1)
<
boost::lambda::bind(&A::a, boost::lambda::_2));
std::for_each(vec.begin(),vec.end(), std::cout << boost::lambda::_1 << ' ');
std::cout << std::endl;
}
Output:
1:0 3:0 4:0 0:0 2:0
0:0 1:0 2:0 3:0 4:0
why not copy the vector into a set:
std::copy(v.begin(),v.end(),std::inserter(s,s.end()));
Now the elements in the set are sorted in ascending order and use set now.
A one liner call to sort() : sort(my_vector_of_class_object.begin(),my_vector_of_class_object.end(),compare);
Code of a working demo of a "sort vector of class objects" is provided below:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class my_Class
{
public:
my_Class(int r,int n, int s):rollno(r),name(n),status(s) { }
int getRollno() const { return rollno;}
int getName() const { return name;}
int getStatus() const { return status;}
private:
int rollno;
int name;
int status;
};
bool compare(const my_Class& x, const my_Class& y) {
return x.getRollno() < y.getRollno();
}
int main()
{
vector<my_Class> my_vector_of_class_object;
vector<my_Class>::const_iterator iter;
my_Class s1(10,20,30);
my_Class s2(40,50,60);
my_Class s3(25,85,9);
my_Class s4(1,50,2);
my_Class s5(90,70,90);
my_Class s6(85,85,3);
my_Class s7(20,6,89);
my_Class s8(70,54,22);
my_Class s9(65,22,77);
my_vector_of_class_object.push_back(s1);
my_vector_of_class_object.push_back(s2);
my_vector_of_class_object.push_back(s3);
my_vector_of_class_object.push_back(s4);
my_vector_of_class_object.push_back(s5);
my_vector_of_class_object.push_back(s6);
my_vector_of_class_object.push_back(s7);
my_vector_of_class_object.push_back(s8);
my_vector_of_class_object.push_back(s9);
cout <<"Before vector sort \n";
for(iter=my_vector_of_class_object.begin(); iter!=my_vector_of_class_object.end();++iter)
std::cout << (*iter).getRollno() << '\t' << (*iter).getName() << '\t' << (*iter).getStatus() << '\n';
cout <<" \n\n";
sort(my_vector_of_class_object.begin(),my_vector_of_class_object.end(),compare);
cout <<"After vector sort \n";
for(iter=my_vector_of_class_object.begin(); iter!=my_vector_of_class_object.end();++iter)
std::cout << (*iter).getRollno() << '\t' << (*iter).getName() << '\t' << (*iter).getStatus() << '\n';
cout <<" \n\n";
return 0;
}