C++ binary search for a class - c++

I have a class and I want to implement binary_search (from library) to it:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class T_value{
public:
T_value(const int _timestamp, const string _value) :
timestamp(_timestamp),
value(_value)
{}
int get_time() {return timestamp;}
private:
int timestamp;
string value;
};
int main()
{
T_value one(1, "one"),
two(3, "two"),
three(43, "three"),
four(-1, "four");
vector<T_value> v{one,two,three, four};
cout << binary_search(begin(v), end(v), 3);
}
Is that possible? Should I overload '==' and '<' operators (tried, didn't succeed) or something else?
Thank you in advance!

Since you send an int as the 3rd argument to binary_search,
just an operator< will not be enough, because you need to
support both int<T_value and T_value<int
The suggestion is to create a comparator class with the members:
bool operator()(const T_value& lhs, int rhs) const
bool operator()(int lhs, const T_value& rhs) const
and send an instance as a fourth parameter.
Furthermore, the vector should be sorted before binary_search is
invoked. You could do this with std::sort, but now you need to
support a 3rd type of comparison, a 3rd member of the comparator
class could do that, like:
bool operator()(const T_value& lhs, const T_value& rhs) const
The end result might look something like this

Yes. Although you just need to implement operator<. Also the argument to binary_search is mismatched and the container must be pre-sorted.
Link to working example:
http://coliru.stacked-crooked.com/a/0343dd205abac6f2
Operator less:
bool operator<(const T_value& other) const {
return timestamp < other.timestamp;//you may wan't another sort criteria
}
Pre-sort container and binary_search:
std::sort(v.begin(), v.end());
cout << (binary_search(begin(v), end(v), T_value(3, "not used") ) ? "found" : "not found") << std::endl;

Related

Finding a C++ object in the set by object comparision instead of using functors

I want to populate a std::set of GraphNode objects and check if another GraphNode with the same value exists in the set. In Java, objects can be compared by overloading equals and compareTo methods, instead of creating some functor object. I implemented operator==(T& t) and expected to find the object in the set like this,
std::find(nodesSet->begin(),nodesSet->end(), new GraphNode<T>(1))!=nodesSet->end())
But I am not getting the break point in neither == nor ()() operator functions. Why is it so? Is there a way to find the object by object comparison?
template<class T>
class GraphNode
{
friend class Graph<T>;
friend bool operator==(GraphNode<T>& node1, GraphNode<T>& node2);
private:
T t;
std::vector<GraphNode<T>*> adjNodes;
public:
bool operator==(T& t);
};
template<class T>
inline bool GraphNode<T>::operator==(T & t)
{
return this->t == t ? true : false;
}
template<class T>
inline bool operator==(GraphNode<T>& node1, GraphNode<T>& node2)
{
return node1.t == node2.t ? true : false;
}
void populate()
{
std::set<GraphNode<T>*>* nodesSet = new set<GraphNode<T>*>;
nodeSet->insert(new GraphNode<T>(1));
nodeSet->insert(new GraphNode<T>(2));
if ( std::find( nodesSet->begin(),nodesSet->end(),
new GraphNode<T>(1) ) != nodesSet->end() )
{
cout<<"found value";
}
}
As aschepler pointed out, the problem with your code is that you end up comparing pointers, not objects. std::find (look at the possible implementations in the linked page), if called without a predicate, uses the == operator to compare what is returned when the iterators you give it are dereferenced. In your case, you have a std::set<GraphNode<T>*> nodesSet, so the type of *nodesSet.begin() is GraphNode<T>*, not GraphNode<T> (note the lack of star). In order for you to be able to use the == operator defined for your GraphNode, you need to have your set be std::set<GraphNode<T>>, that is of objects of your type rather than of pointers.
If you have to store pointers in your set (e.g. because you don't want to copy the objects), you can write a wrapper for pointers that uses the comparison operator for the underlying class of the pointers. Here's an example:
#include <iostream>
#include <set>
#include <algorithm>
class obj {
int i;
public:
obj(int i): i(i) { }
bool operator<(const obj& o) const { return i < o.i; }
bool operator==(const obj& o) const { return i == o.i; }
int get() const { return i; }
};
template <typename T>
class ptr_cmp {
T* p;
public:
ptr_cmp(T* p): p(p) { }
template <typename U>
bool operator<(const ptr_cmp<U>& o) const { return *o.p < *p; }
template <typename U>
bool operator==(const ptr_cmp<U>& o) const { return *o.p == *p; }
T& operator*() const { return *p; }
T* operator->() const { return p; }
};
int main(int argc, char* argv[])
{
obj five(5), seven(7);
std::set<ptr_cmp<obj>> s;
s.insert(&five);
s.insert(&seven);
obj x(7);
std::cout << (*std::find(s.begin(),s.end(), ptr_cmp<obj>(&x)))->get()
<< std::endl;
return 0;
}
It turned out that my compiler (gcc 6.2.0) required both operator== and operator< for std::find to work without a predicate.
What is wrong with using a predicate though? It is a more generalizable approach. Here's an example:
#include <iostream>
#include <set>
#include <algorithm>
class obj {
int i;
public:
obj(int i): i(i) { }
bool operator==(const obj& o) const { return i == o.i; }
int get() const { return i; }
};
template <typename T>
struct ptr_cmp {
const T *l;
ptr_cmp(const T* p): l(p) { }
template <typename R>
bool operator()(const R* r) { return *l == *r; }
};
template <typename T>
ptr_cmp<T> make_ptr_cmp(const T* p) { return ptr_cmp<T>(p); }
int main(int argc, char* argv[])
{
obj five(5), seven(7);
std::set<obj*> s;
s.insert(&five);
s.insert(&seven);
obj x(7);
std::cout << (*std::find_if(s.begin(),s.end(), make_ptr_cmp(&x)))->get()
<< std::endl;
return 0;
}
Note, that make_ptr_cmp allows you to avoid explicitly stating the type, so you can write generic code.
If you can use C++11, use can just use a lambda function instead of ptr_cmp,
std::find_if(s.begin(),s.end(), [&x](const obj* p){ return *p == x; } )
std::find compares the values pointed at by the iterators. These values are pointers, not objects. So none of them will be equal to new GraphNode<T>(1), which is a brand new pointer to a brand new object.
As others have stated, you are comparing pointers, which won't work as expected, it's doing comparisons on addresses in memory. The operation a < b has a valid meaning for a pointer but will order the elements by their location in memory, not on their contained data elements and also no elements will be unique, as they will all have unique addresses. That is unless you try to insert the same element twice.
The above issue however will be hidden by using std::find, which iterates over all the elements in the container anyway. If you are using a set, you should be aspiring to get logarithmic time look ups for elements, so should use sets own find function, which knows that its a binary tree under the hood.
In C++, the equivalent of Object#equals is operator== (as you knew) and in the context of associative containers the equivalent of Object#compareTo is operator<. Object#equals and operator== work in the same way, exactly as you expect; If somethings equal its equal, simple to understand. Object#compareTo and operator< are used by algorithms in different ways, operator< is used to implement strict weak ordering to determine if one element is less than or greater than another.
So to allow your elements to be usable in a set you will need an overridden operator< in your GraphNode class. Once you have this you can use the std::set::find function to find elements in your set and it will find them in O(log n) time rather than linear time.
These algorithms are designed on the assumption they are working on value types, i.e not pointers but those things that are pointed to. So to use pointers you need to define a new comparison function that basically dereferences the pointers before applying the comparison (either == or <).
Some example code
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
template<typename>
class Graph
{
};
template<class T>
class GraphNode
{
friend class Graph<T>;
friend bool operator==(const GraphNode<T>& a, const GraphNode<T>& b);
private:
T t;
std::vector<GraphNode<T>*> adjNodes;
public:
explicit GraphNode(const T& tval)
:t(tval)
{}
T& getT(){ return t; }
const T& getT() const { return t; }
bool operator==(const T& t);
friend bool operator<(const GraphNode& a, const GraphNode& b){
return a.t < b.t;
}
};
template<class T>
inline bool GraphNode<T>::operator==(const T& t)
{
return (this->t == t);
}
template<class T>
inline bool operator==(const GraphNode<T>& a, const GraphNode<T>& b)
{
return (a.t == b.t);
}
int main()
{
using IntGraphNode = GraphNode<int>;
std::set<IntGraphNode> nodesSet;
nodesSet.insert(IntGraphNode(1));
nodesSet.insert(IntGraphNode(2));
auto findit = nodesSet.find(IntGraphNode(1));
if(findit != nodesSet.end())
{
std::cout << "found value\n";
}
auto findit2 = std::find_if(
nodesSet.begin(),
nodesSet.end(),
[](IntGraphNode i) { return i.getT() == 1;});
if(findit2 != nodesSet.end())
{
std::cout << "found value aswell\n";
}
}
The first search uses sets own find function and the second uses std::find_if, which takes a predicate (function that returns either true or false) to test equality. The second example also removes the need to make a dummy object, by exposing the T object and using that in the comparison lambda function.
Also a comment about
std::find(nodesSet->begin(),nodesSet->end(), new GraphNode<T>(1))!=nodesSet->end())
There are quite a few conceptual misunderstandings in this line. Firstly std::find does not take a comparison function, that would be std::find_if, but the compiler will tell you that (in its own especially indirect and verbose way). Also the comparison function is evaluated in the algorithm, you are trying to evaluate it at the call site. The other thing is unlike java, you can't just fire off newed objects into oblivion. That's a memory leak, you no longer have any variable storing the newed value, so you can't delete it.

Use member functions directly with unordered_set

Is there a short-cut to using std::unordered_set with classes that implement operator== and hash? Specifically, is there a way to (1) avoid creating a stand-alone operator==(const Object& a, const Object& b) function, and (2) avoid defining an entire class just to hold size_t operator()(const Object& o) const {return o.hash();}
Of course, neither of these are problems, I'm just curious.
operator== being defined as a member function is already catered for.
If the class being used as a key has a member function hash() const then we can do something simple like this:
-
#include <unordered_map>
#include <string>
struct myclass {
std::size_t hash() const { return 0; }
bool operator==(const myclass& r) const { return true; }
};
struct self_hash
{
template<class T>
auto operator()(const T& r) const { return r.hash(); }
};
int main()
{
using mymap = std::unordered_map<myclass, std::string, self_hash>;
auto m = mymap();
}

Multiple Overloading of Operators

as you can see from the code I want to overload the < operator twice. 1 to sort by dist and the other by nodeID. I would like to check if there is any way to call the different overloaded methods. For example in the compLoc method, when I use the sort() method I want it to be sorted by nodeID but in other methods I want it to be sorted by dist.
struct AttSet{
int nodeID;
double dist;
bool operator < (const AttSet & str) const{
return (dist < str.dist);
}
/*
bool operator <(const AttSet & str){
return (nodeID < str.nodeID);
*/
bool operator == (const AttSet & str){
return nodeID == str.nodeID;
}};
void compLoc(Edge *edge, vector<Node*> &vertices){
int l = edge->length;
int vl = edge->head->nodeID;
int vr = edge->tail->nodeID;
/*
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end());
sort(vertices[vr]->attSet.begin(), vertices[vr]->attSet.end());
vector<AttSet> vInterSec;
set_intersection(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), vertices[vr]->attSet.begin(), vertices[vr]->attSet.end(), back_inserter(vInterSec));
*/}
You cannot have overloads that have the same signature. This holds for any function. How would you try to decide which version to use?
If you want sort the object based on different criteria you should use the sort version that takes a custom comparer function as the third argument.
Edit:
Of course you need to provide the comparer. I would suggest providing the comparers as static functions of the class if you have such power. This way you will not pollute enclosing namespace and you can access privates of the class with out exposing any getters. Since your properties are public the lambda would suffice, and probably be the best/cleanest approach.
Feeling adventurous I made a simple c++11 exercise program. For what it's worth, if you ever decided to go for proper encapsulation, I've shown both approaches:
#include <iostream>
#include <algorithm>
#include <vector>
#include <initializer_list>
#include <cassert>
using namespace std;
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v){
for(const auto& el : v){
out << el << '\n';
}
return out;
}
class A {
int a;
int b;
public:
A(std::initializer_list<int> l){
assert(l.size() == 2);
auto i = l.begin();
a = *i;
++i;
b = *i;
}
friend std::ostream& operator<<(std::ostream& stream, const A& e){
return stream << e.a << ' ' << e.b;
}
static bool compareViaA(const A& lhs, const A& rhs){
return rhs.a > lhs.a;
}
static bool compareViaB(const A& lhs, const A& rhs){
return rhs.b > lhs.b;
}
};
int main() {
std::vector<A> v {{2,3}, {3,2}, {1,4}, {4,1}};
//sort(v.begin(), v.end(), [](const A& a, const A& b){return a.a > b.a;}) // fails because of privacy violation
sort(v.begin(), v.end(), A::compareViaA);
std::cout << v << '\n';
sort(v.begin(), v.end(), A::compareViaB);
std::cout << v << '\n';
return 0;
}
Live: http://ideone.com/lDMujx.
I think you can implement this by using functor and take the comparator(operator< overload) outside the AttSet.
Here is a simple example:
struct AtrComparator {
bool distcmp;
AttrComparator(bool distcmp): distcmp(distcmp) {}
bool operator() (const AttSet &s1, const AttSet &s2) {
if(distcmp) {
return s1.dist < s2.dist;
} else {
return s1.nodeID < s2.nodeID;
}
}
}
And then you can do the sort through different feed, dist or nodeID.
.e.g:
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(true));
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(false));
You can't do that. They have the same signature exactly.
Use a functor or a lambda and pass it to whatever algorithm you want.
std::sort(std::begin(container), std::end(container),
[](const element_type& lhs, const element_type& rhs) { return ...; });
Another way to do this:
struct compare_by_node_id {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.nodeID < rhs.nodeID;
}
};
struct compare_by_dist {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.dist < rhs.dist;
}
};
And you could pass that to the algorithm like:
std::sort(std::begin(container), std::end(container), compare_by_node_id());
you cannot do that because compiler doesn't see difference between:
bool operator < (const AttSet & str) const; //this const doesn't allow to override any property of object(instance of AttSet) if I remember
and
bool operator < (const AttSet & str);
there're the same same return type, same parameter (same signature)
compiler cannot choose which one is better
There's not a great way to do this as far as I am aware, since the compiler will see these as the exact same and will throw an error. If you need to do this, use the < operator as whatever will occur the most often, and then write a method that you can call to compare two object. Something like this:
bool operator< (const Blah &blah) const {
return (most often operation)
}
bool Blah::other_operation(const Blah &blah) const {
return (other operation)
}

C++ Vector Range Constructor

I was looking over some C++ documentation when it occurred to me that the vector container doesn't have a constructor that 'easily' allows the user to pass a range of values - a min and a max - and have a vector constructed which has elements from min -> max. I thought this was odd so I tried writing my own and discovered it was non-trivial. Here's my solution.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <typename T>
class MyIterator: public std::iterator<std::input_iterator_tag, int>
{
public:
MyIterator(T val):value(val) {}
MyIterator(const MyIterator & m):value(m.value) {}
MyIterator& operator ++()
{
++value;
return *this;
}
MyIterator operator ++(int)
{
MyIterator temp(*this);
operator ++();
return temp;
}
bool operator ==(const MyIterator & m) const { return value == m.value; }
bool operator !=(const MyIterator & m) const { return !(value == m.value); }
T& operator *() { return value; }
private:
T value;
};
int main(int argc, char** argv)
{
std::vector<int> my_vec(MyIterator<int>(100), MyIterator<int>(400));
std::copy(my_vec.begin(), my_vec.end(), std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}
Does the new C++ have a solution for this?
In C++11 there is the std::iota function. Otherwise you have e.g. std::fill and std::fill_n, or std::generate and std::generate_n.
For C++11 there was no substantial work on changing the algorithms or containers to make them easier usable (there are a couple of new algorithms and the containers were made aware of allocators and rvalues). Neither is there a substantial change for C++14.
There is some hope for C++17, though: the Ranges Study Group is looking at concepts to make the algorithms and containers easier to use. That said, it isn't clear where that journey will travel to.

Why i need to use the const function in the Less Traits

why i need to use the const function in the less traits?
for example, why i must use const in Age or ID member function.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <string>
#include <set>
using namespace std;
class Person
{
public:
Person(int id, string name, int age):m_iID(id), m_strName(name), m_iAge(age){};
int Age() const {return m_iAge;}
int ID() const {return m_iID;}
void Display();
friend ostream& operator<<(ostream& out, Person& person);
private:
int m_iID;
string m_strName;
int m_iAge;
};
void Person::Display()
{
cout<<m_iID<<" "<<m_strName<<" "<<m_iAge<<endl;
}
ostream& operator<< (ostream& out, Person& person)
{
out<<person.m_iID<<" "<<person.m_strName<<" "<<person.m_iAge<<endl;
return out;
}
int SumPersonAge(int iSumAge, Person& person)
{
return iSumAge + person.Age();
}
template <typename Type>
void Display(Type t1)
{
cout<<t1<<endl;
}
class LessPerson
{
public:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
int main()
{
set<Person, LessPerson> s1;
Person p1(1234, "Roger", 23);
Person p2(1235, "Razor", 24);
s1.insert(p1);
s1.insert(p2);
for_each(s1.begin(), s1.end(), Display<Person>);
}
if i remove the const the keyword in Age or ID function, the compiler will report me Error cannot convert 'this' pointer from 'const Person' to 'Person &'.
The answer is that the set will pass two const reference to Person objects to your comparator, and you cannot call a non-const function on a const variable.
You might be surprised as there seems not to be any const in the declaration of the functor:
struct LessPerson
{
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
But there is, it is just not explicit in the code. Inside the set implementation there are two const Person& references (call them r1, r2) and a LessPerson comparator (call it compare) and the code does something in the lines of if ( comparator(r1,r2) ). The compiler finds the templated operator() and tries to infer the types ending up with the type substitution: Type == const Person.
Why does the set use const references rather than plain modifiable references? Well, that is a different issue. The set is implemented as a sorted balanced tree, with each node containing the key. Now because a change in the key would break the order invariant, the keys are themselves const objects, ensuring that you cannot break the invariants.
That const keyword means that the function does not modify its object, this. Only const functions may be called from const objects. So, the compiler is telling you that you are trying to call a non-const member function from a const object.
You appear to be avoiding the const keyword, but it creeps in when the library calls your template function:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
Type is passed as const Person.
const is not easy to get rid of without cheating, and it will always creep in. It's better to go with the flow and add const everywhere you take a reference that doesn't change an object (which is most of them).
Because the type passed to LessPerson is const Person.
So basically, LessPerson is roughly
class LessPerson   
{
public:
bool operator()(const Person& t1, const Person& t2)
{
return t1.ID() < t2.ID();
}
};
You can't call non-const methods on const objects. It's a rule of C++.