I have custom binary tree class that holds values of template type T (it could be value or pointer). Each value is encapsulated with number (this number is used for searching in tree). I want to have an std::map inside my tree class fo fast O(1) access to objects without numbers.
template <typename T>
stuct BSTNode
{
T value;
int searchValue;
}
template <typename T>
class BST
{
BSTNode<T> * root;
std::map<T, BSTNode<T>> cache;
//... etc.
}
Example: I have class instance a inserted in tree under value n. Now I want to get the node associated with this a. I cannot search the tree, because I don't have n. So I want to use a, and from std::map get node = map[a]. Now I can do node->n.
How can I achieve this? I can override compare method of std::map:
bool operator()(const void * s1, const void * s2) const
But it doesn't work for value and pointer at the same time: cannot convert parameter 1 from const double to const void *.
Make a traited comparator:
template <typename T>
struct NodeComp
{
bool operator<(T const & lhs, T const & rhs) const
{
return lhs < rhs;
}
};
template <typename U>
struct NodeComp<U *>
{
bool operator<(U * lhs, U * rhs) const
{
return *lhs < *rhs;
}
};
Now your map can be defined like so:
template <typename T>
class BST
{
BSTNode<T> * root;
std::map<T, BSTNode<T>, NodeComp<T>> cache;
}
Related
I am trying to get Predecessor and Successor of a vertex from a directed graph implemented with adjacency list.
here s a brief description of my class :
template <class T>
class Digraph
{
public:
Digraph();
~Digraph();
void predecessor(T u);
void successor(T u, T v);
private:
std::map<T, std::set<T>> graphe;
}
Here is what I tried :
template <class T>
const std::set<T> Digraph<T>::predecessor(T u) const
{
std::set<T> p;
int index = 0;
for (auto it = graphe.begin(); it != graphe.end(); ++it, index++)
{
for(T el : *it) //I got the error here
{
if (el == u)
p.insert(index);
}
}
return p;
}
template <class T>
const std::set<T> Digraph<T>::successor(T u) const
{
return graphe.at(u);
}
I get the error in the inner loop.
Does anyone have an idea for an implementation? or can help me by telling me what i forgot.
Searching through the entire graph to find predecessors is a possibly costly operation. You would make your life much easier if you just stored all back-edges in a separate, identical structure:
std::map<T, std::set<T>> inverted;
Then, your member functions would be quite trivial:
template <typename T>
std::set<T> const& Digraph<T>::successor(T const& v) const {
return graph.at(v);
}
template <typename T>
std::set<T> const& Digraph<T>::predecessor(T const& u) const {
return inverted.at(u);
}
Note that the return type is an std::set<T> const& instead of an std::set<T>. This means that you don't copy the entire set.
For insertion the code becomes:
graph[v].insert(u);
inverted[u].insert(v); // new line
However, if you really want to keep your expensive lookup, maybe because it happens really seldom you can do it like this:
template <class T>
std::set<T> Digraph<T>::predecessor(T const& u) const {
std::set<T> p;
for (auto const& [v, set]: graph)
for(auto const& w : set)
if (u == w) {
p.insert(v);
break;
}
return p;
}
Please note however, that this will create copies of the values stored in your graph. If you only have integers, that's no issue. But if you have class-objects in there, copying might not be what you want.
template <typename Key, typename E>
class BST : public Dictionary<Key, E>
{
.....
E FindHelp(BSTNode<Key, E>*, const Key&) const;
template <typename Key>
std::string FindHelp(BSTNode<Key, std::string> *root, const Key &k) const;
....
};
template <typename Key>
std::string BST<Key, std::string>::FindHelp(BSTNode<Key, std::string> *root, const Key &k) const
{
if (root == nullptr) return "Not Found!"; // Empty tree
// If smaller than the root go left sub tree
if (k < root->key()) return FindHelp(root->Left(), k);
// If bigger than the root go right tree
if (k > root->key()) return FindHelp(root->Right(), k);
// If equal to the root return root value
else return root->Element();
}
I want to add a function dealing with specific data type like std::string, when i wrote my definition like this
error C2244: 'BST::FindHelp': unable to match
function definition to an existing declaration
There is no partial function template specialization. You can only use partial template specialization for class, so you have to partially specialize for BST class first.
template <typename Key, typename E>
class BST : public Dictionary<Key, E>
{
E FindHelp(BSTNode<Key, E>*, const Key&) const;
};
template<typename Key>
class BST<Key, std::string> : public Dictionary<Key, std::string>
{
std::string FindHelp(BSTNode<Key, std::string>*, const Key&) const;
};
template <typename Key>
std::string BST<Key, std::string>::FindHelp(BSTNode<Key, std::string> *root, const Key &k) const
{
}
I'm creating a container class which implements a double linked list.
template <class T>
class dl_list {
public:
class link {
public:
T* data;
link *prev, *next;
};
class iterator {
link* node;
public:
link* get_node() { return node; }
// ++, --, * operators, etc.
};
// other stuff
};
Pretty neat, I'm having fun with it. But one problem I'm having is when I define my equality operators for the iterator type, I have to do a template specialization.
template <class T>
bool operator==(typename dl_list<T>::iterator& lhv, typename dl_list<T>::iterator rhv) {
return lhv.get_node() == rhv.get_node();
}
will not work, I have to specialize it like so:
bool operator==(typename dl_list<int>::iterator& lhv, typename dl_list<int>::iterator rhv) {
return lhv.get_node() == rhv.get_node();
}
for every type I want to use it for, which is annoying for obvious reasons. How do I get around this?
Make it a member of the iterator class:
bool operator==( const interator& other ) const
{
return node == other.node;
}
You can't. The compiler cannot know that some T is a nested type of some other U. Consider
template<> class dl_list<float> {
public:
typedef dl_list<int>::iterator iterator;
};
You have to take the iterator type directly as the template parameter, or define it as a member of the iterator class, or define the iterator class outside dl_list and simply make a typedef for it inside dl_list.
Easiest cleanest way is to define the operator inside the iterator class:
class iterator
{
public:
...
friend bool operator==(iterator& lhs, iterator& rhs)
{
return lhs.get_node() == rhs.get_node();
}
};
(Bit of a code smell here - I'd have expected get_node() to have a const version, allowing the operator== to accept parameters by const reference...)
To narrow it down: I'm currently using Boost.Unordered. I see two possible solutions:
Define my own Equality Predicates and Hash Functions and to utilize templates (maybe is_pointer) to distinct between pointers and instances;
Simply to extend boost::hash by providing hash_value(Type* const& x) as for hashing; and add == operator overload as free function with (Type* const& x, Type* const& y) parameters as for equality checking.
I'm not sure whether both variations are actually possible, since I didn't test them. I would like to find out you handle this problem. Implementations are welcome :)
EDIT 1:
What about this?
template<class T>
struct Equals: std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
return left == right;
}
};
template<class T>
struct Equals<T*> : std::binary_function<T*, T*, bool> {
bool operator()(T* const& left, T* const& right) const {
return *left == *right;
}
};
EDIT 2:
I've just defined:
friend std::size_t hash_value(Base const& base) {
boost::hash<std::string> hash;
return hash(base.string_);
}
friend std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
And then:
Derived d1("x");
Derived d2("x");
unordered_set<Base*> set;
set.insert(&d1);
assert(set.find(&d2) == end());
Debugger says that friend std::size_t hash_value(Base* const& base) is never called (GCC 4.7). Why is that?
EDIT 3:
I found out that template <class T> std::size_t hash_value(T* const& v) in boost/functional/hash.hpp on line #215 (Boost 1.49) is Boost's specialization for pointers and it simply masks your custom implementation of hash_value such as mine in EDIT 2.
Therefore, it seems like the only way here is to create a custom Hash Functor.
For the hash function, you have a choice between specializing boost::hash (or std::hash in the newer standard) or defining a new functor class. These alternatives work equally well.
For the equality operator, you need to define a new functor, because you cannot redefine the equality operator over pointers. It's a built-in operator (defined in functional terms as bool operator==( T const *x, T const *y )) and cannot be replaced.
Both of these can be defined generically by using a templated operator() in a non-templated class.
struct indirect_equal {
template< typename X, typename Y >
bool operator() ( X const &lhs, Y const &rhs )
{ return * lhs == * rhs; }
};
Follow a similar pattern for the hasher.
Taking into consideration all edits in the original post I would like to provide complete solution which satisfies my needs:
1. Equality:
template<class T>
struct Equal: ::std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
::std::equal_to<T> equal;
return equal(left, right);
}
};
template<class T>
struct Equal<T*> : ::std::binary_function<T*, T*, bool> {
bool operator()(T* const & left, T* const & right) const {
Equal<T> equal;
return equal(*left, *right);
}
};
2. Hashing:
template<class T>
struct Hash: ::std::unary_function<T, ::std::size_t> {
::std::size_t operator()(T const & value) const {
::boost::hash<T> hash;
return hash(value);
}
};
template<class T>
struct Hash<T*> : ::std::unary_function<T*, ::std::size_t> {
::std::size_t operator()(T* const & value) const {
Hash<T> hash;
return hash(*value);
}
};
So now I can continue using Boost's hash_value and it will not get masked for pointer types by Boost's default implementation (see EDIT 3).
3. Example:
In my application I have a thin wrapper for unordered_set which now looks like that:
template<class T, class H = Hash<T>, class E = Equal<T> >
class Set {
public:
// code omitted...
bool contains(const T& element) const {
return s_.find(element) != end();
}
bool insert(const T& element) {
return s_.insert(element).second;
}
// code omitted...
private:
::boost::unordered::unordered_set<T, H, E> s_;
};
So if we have some base class:
class Base {
public:
Base(const ::std::string& string) {
if (string.empty())
throw ::std::invalid_argument("String is empty.");
string_ = string;
}
virtual ~Base() {
}
friend bool operator==(const Base& right, const Base& left) {
return typeid(right) == typeid(left) && right.string_ == left.string_;
}
friend bool operator!=(const Base& right, const Base& left) {
return !(right == left);
}
friend ::std::size_t hash_value(Base const& base) {
::boost::hash<std::string> hash;
return hash(base.string_);
}
friend ::std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
private:
::std::string string_;
};
And some derived class:
class Derived: public Base {
public:
Derived(const ::std::string& string) :
Base(string) {
}
virtual ~Derived() {
}
};
Then we can even use polymorphism (which was my primary intention BTW):
Derived d1("¯\_(ツ)_/¯");
Derived d2("¯\_(ツ)_/¯");
Set<Base*> set;
set.insert(&d1);
assert(set.contains(&d2));
Hope this helps. Any suggestions are welcome.
I'm having troubles in overloading comparison operators in order to compare two pair struct in such way:
typedef pair<string, unsigned int> INDEX;
bool operator>(INDEX &v1, INDEX &v2)
{
if(v1.second == v2.second) //if integer parts are equal
{
//string that comes earlier in the dictionary should be larger
return v1.first < v2.first;
}
return v1.second > v2.second;
}
The actual comparison takes place at this->element(hole/2) < this->element(hole) inside fixUp(CBTNODE hole), a member function of BinaryHeap class, which is a derived class of CompleteBinaryTree. The T will be instantiated as type INDEX, which is typedefed as pair<string, unsigned int>.
In other words, the comparison between two pairs: ("a.txt", 42) > ("b.txt", 42) should return true.
I tried to overload operator> outside the class declaration in two different ways but neither of them worked:
bool operator>(INDEX &v1, INDEX &v2);
bool operator>(BinaryHeap<T> &v1, BinaryHeap<T> &v2);
Any help will be much appreciated!
Z.Zen
Here is the declarations:
typedef int CBTNODE;
template <typename T>
class CompleteBinaryTree {
public:
//Initializes an empty binary tree
CompleteBinaryTree(int initialSize = 10);
//Destructor
~CompleteBinaryTree();
//Returns the element of the CBT pointed to by node. Behavior is undefined
//if node does not exist.
T element(CBTNODE node);
protected:
T *data;
int numElts, maxElts;
};
typedef pair<string, unsigned int> INDEX;
template <typename T>
class BinaryHeap : public CompleteBinaryTree<T>
{
public:
//Maintain heap property with bottom up heapify method.
void fixUp(CBTNODE hole);
};
bool operator>(INDEX &v1, INDEX &v2);
Implementation:
template <typename T>
T CompleteBinaryTree<T>::element(CBTNODE node) {
assert(node >= 0);
assert(node < numElts);
return data[node];
}
template <typename T>
void BinaryHeap<T>::fixUp(CBTNODE hole)
{
T tmp = this->element(hole);
while( hole > 0 && this->element(hole/2) < tmp )
{
//do stuff
}
}
bool operator>(INDEX &v1, INDEX &v2)
{
if(v1.second == v2.second) //if two have same relevance
{
return v1.first < v2.first;
}
return v1.second > v2.second;
}
A temporary, such as the result of element func, cannot be bound to a reference to non-const, such as the formal arguments of your operator>.
Declare it thusly:
bool operator>( INDEX const& v1, INDEX const& v2 )
However, the implementation that you present doesn't seem to be correct for operator>.
And while I'm at it, what you want is really operator< instead, because that's the one required by standard algorithms. Perhaps combined with an operator== (because it's inefficient to synthesize it from operator<). With those two any relationship can be checked for relatively efficiently.
Btw., if you stop using ALL UPPERCASE names for anything else then macros (see the FAQ), then you can avoid inadvertent name collision with macros.
Cheers & hth.,
Don't typedef INDEX, be explicit:
template<class F, class S>
struct Index {
std::pair<F, S> Value;
Index(const std::pair<F, S>& pValue)
: Value(pValue) {}
};
template<class F, class S>
bool operator<(const Index<F, S>& pLeft, const Index<F, S>& pRight) {
// your implementation...
}