I have a Node class with the members
int weight;
Node *left;
Node *right;
I want to create a heap by using the STL functions
make_heap(Iterator , Iterator, comp)
pop_heap(Iterator, Iterator, comp)
to apply on a vector of Node pointers. How can I create a comparison object (or comparison function) for those functions?
struct node_comparison : public std::binary_function< const Node*, const Node*, bool >
{
bool operator()( const Node* const a, const Node* const b ) const
{
return a->weight < b->weight;
}
};
Note that this comparsion object compares only the weights, but I assume this is desired behaviour.
If you provide strict weak ordering via a operator< for your object you can call the overload of make_heap, pop_heap, etc which don't even need the third argument. comp is so you can provide a custom comparison if you choose.
class Node
{
int weight;
Node *left;
Node *right;
public:
bool operator<(const Node& rhs) const { return weight < rhs.weight; }
};
Related
I've implemented a balanced binary search tree (Red-black tree) for practice purposes. here is the header of data-structure of underlying nodes and methods I've implemented so far:
#ifndef BST_H
#define BST_H
template <typename T>
class treeNode {
public:
treeNode *left;
treeNode *right;
T key;
treeNode(T key)
: key(key)
, left(nullptr)
, right(nullptr) {
}
};
template <typename T>
class BST {
public:
BST() {
root = nullptr;
nodes = 0;
}
BST(BST const& rhs);
BST& operator = (BST rhs) {
this->swap(rhs);
}
BST& operator = (BST&& rhs) {
this->swap(rhs);
}
~BST() {
clear(root);
}
void swap(BST& other) {
std::swap(root, other.root);
std::swap(nodes, other.nodes);
}
void clear(treeNode<T>* node) {
if(node) {
if(node->left) clear(node->left);
if(node->right) clear(node->right);
delete node;
}
}
bool isEmpty() const {
return root == nullptr;
}
void inorder(treeNode<T>*);
void traverseInorder();
void preorder(treeNode<T>*);
void traversePreorder();
void postorder(treeNode<T>*);
void traversePostorder();
void insert(T const& );
void remove(T const& );
treeNode<T>* search(const T &);
treeNode<T>* minHelper(treeNode<T>*);
treeNode<T>* min();
treeNode<T>* maxHelper(treeNode<T>*);
treeNode<T>* max();
size_t size() const;
void sort();
treeNode<T>* inOrderSuccessor(treeNode<T>*);
bool isBST(treeNode<T>*) const;
bool isBST() const;
private:
treeNode<T> *root;
size_t nodes;
};
#endif
I intend to implement C++ STL map (I've already implemented STL unordered_map using Hashtable) for which the underlying data-structure is Red-Black Tree AFAIK. How I can extend my tree to a key-value generic type map?
No need of any sort of source code. Some intuition will suffice. Thanks :)
With intuition: T will probably be pair<const key_type,mapped_type>. I'm Assuming that currently you use node.key < another_node.key for comparisons. That will not do, because a map should be only using the first part of the pair for that. You could add a Compare functor as a template parameter (in similar manner as you'll have to for your map class) to your tree to make it useful for implementing a stl compatible map.
You may choose to design your tree so that key and value classes are separate rather than combined. Here's example code for the template definition:
template<class Key, class Value, class Comp=std::less<Key>>
class BST {
Compare comp;
public:
BST(const Comp& comp = Comp()): comp(comp)
//...
// usage
if(comp(node.key, another_node.key)) {
// node is considered to be strictly before another_node
You can use std::less as a sensible default parameter for other users of the tree, but the map implementation should forward the comparator which was given for the map.
A fully stl compatible container should support custom allocators too and to make that possible, so must the internal tree structure.
I have this class called "Node". I've been considering renaming it "Tree", but either name makes about as much sense. This class implements a generic tree container. Each node can have any number of children. The basic header definition of the class is as follows:
template<class Elem>
class Node
{
public:
Node();
~Node();
Node(const Elem& value);
Node(const Node& rNode);
const Elem& operator*() const;
Elem& operator*();
Elem* operator->();
void operator=(const Elem& rhs);
Node* addChild(const Elem& value);
Node* addChild(Node childNode);
Node* addChild(Node* pChildNode);
HRESULT removeNode(DFSIterator<Node>& iter);
template <class Node, class List, class Iter> friend class DFSIterator;
private:
bool hasChild() const;
Node* m_pParentNode;
Elem m_value;
std::vector<Node*> m_childList;
static std::set<Node*> sNodeSet;
};
The header definition of my DFSIterator is:
template<class Item,
class List = std::vector<Item*>,
class Iter = typename std::vector<Item*>::iterator>
class DFSIterator
{
public:
DFSIterator(Item& rRootNode);
~DFSIterator();
DFSIterator* begin();
DFSIterator* operator++();
Item& operator*() const;
Item* operator->() const;
bool operator!=(const DFSIterator& rhs) const;
bool isDone() const;
operator bool() const {return !isDone();}
private:
template <class Node> friend class Node;
void initChildListIterator(Item* currentNode);
bool m_bIsDone;
Item* m_pRootNode;
Item* m_pCurrentNode;
ChildListIterator<Item>* m_pCurrentListIter;
std::map<Item*, ChildListIterator<Item, List, Iter>*> m_listMap;
};
Item is the iterator's alias for Node<Elem>.
The problem I am having is that I want to define iterators for this tree that the user can declare in a similar way to STL containers. I was thinking that putting typedef statements like typedef DFSIterator<Node<Elem>> dfs_iterator; would work fine. But whenever I add those statements into the header, I get the following error error C2512<Item>: no appropriate default constructor available. Wherever I try to go and use it.
So right now, to declare an iterator I have to do something like DFSIterator<Node<DataMap>> dfsIter = rRootNode.begin(); or DFSIterator<Node<DataMap>> dfsIter(rNode); if I don't want to start at the root node of the tree. What I want to be able to do is something more like Node<DataMap>::dfs_iterator it = rRootNode.begin(). Is there a way to do this that I am missing?
Note: I do want to change a few other things about this implementation. I don't really want the user to be passing a node element to the addChild() method. I'd rather have the user pass an iterator that is pointing to a node.
If you define dfs_iterator inside Node, then you can use it basically like you describe:
template<class Elem>
class Node
{
public:
typedef Node<Elem> Item;
template<
class List = std::vector<Item*>,
class Iter = typename std::vector<Item*>::iterator
> class dfs_iterator;
.
.
.
};
template<class Elem>
template<class List, class Iter>
class Node<Elem>::dfs_iterator
{
public:
.
.
.
};
and use
Node<DataMap>::dfs_iterator<> it = rRootNode.begin();
The only difference is that since dfs_iterator is a template, you have to specify the template parameters, even though they both can be defaulted.
I'm trying to implement a Fibonacci heap of pointers of a class called Node using Boost.
typedef boost::heap::fibonacci_heap<Node*> FibonacciHeap;
typedef FibonacciHeap::handle_type HeapHandle;
So far, so good. But I also want to store handles for the heap elements in the Node class. Boost specifically mentions that "handles can be stored inside the value_type". Boost
However, I can't define a comparison operator inside the class, because the heap never uses it and only compares the pointer values.
But defining a comparison struct which is passed as a template parameter to fibonacci_heap introduces a cyclic dependency:
struct CompareNode : public std::binary_function<Node*, Node*, bool>
{
bool operator()(Node* lhs, Node* rhs) const {
return lhs->getFScore() > rhs->getFScore();
}
};
typedef boost::heap::fibonacci_heap<
Node*,
boost::heap::compare<CompareNode> > FibonacciHeap;
Node depends on HeapHandle and HeapHandle depends on Node.
Try forwarding declaring Node and then defining the operator not inline
// In Node.h
class Node;
struct CompareNode : public std::binary_function<Node*, Node*, bool>
{
bool operator()(Node* lhs, Node* rhs) const;
};
typedef boost::heap::fibonacci_heap<
Node*,
boost::heap::compare<CompareNode> > FibonacciHeap;
typedef FibonacciHeap::handle_type HeapHandle;
class Node{
HeapHandle handle_;
int getFScore();
};
// In Node.cpp
#include "Node.h"
bool CompareNode::operator()(Node* lhs, Node* rhs) const {
return lhs->getFScore() > rhs->getFScore();
}
Let's say we have a priority_queue that holds a bunch of ListNode objects declared as below:
class ListNode {
int val;
ListNode *next;
public:
explicit ListNode(int v) : val(v), next(NULL) {}
inline bool operator<(const ListNode& rhs) const {
return val < rhs.val;
}
};
std::priority_queue<ListNode> pq;
By overriding operator< method or providing a sorting functor we can have the priority_queue hold the ListNode objects in val's ascending order.
My question is if the priority_queue holds the pointers to ListNode class instead can I have the pointers sorted so that the val's pointed are in ascending order. How do I do that?
std::priority_queue<ListNode *> pq1;
Thanks!
As you said, std::priority_queue accepts as third template parameter a comparison functor that it has to use to perform the comparisons.
Just write your own that dereferences the items before comparing them:
template<typename T>
struct PtrLess
{
bool operator()(const T* left, const T* right)
{
return *left < *right;
}
};
std::priority_queue<ListNode *, std::vector< ListNode * >, PtrLess< ListNode > > pq1;
A pointer to ListNode is like an everyday pointer. You cannot overload an operator between two pointers.
However, you can override the comparison operator for the purpose of the priority_queue. It would go something like this:
struct ListNodePtrLess {
bool operator()(const ListNode* a, const ListNode* b) {
return a->val < b->val;
}
};
typedef std::priority_queue<ListNode*, std::vector<ListNode*>, ListNodePtrLess> MyPriorityQueue;
(also: you will need to make ListNodePtrLess a friend of ListNode, or let it access the val field in some different way)
I'm having a little trouble trying to sort a vector of pointers.
This is what I have done so far:
class Node
{
private:
vector <Node*> _children;
string _data;
...
public:
void Node::add_child(Node* child)
{
...
sort(_children.begin(), _children.end());
}
bool Node::operator<(const Node& node)
{
return (this->_data.compare(node._data) == -1);
}
};
My less-than operator works, if I write like this:
Node* root = new Node("abc");
Node* n = new Node("def");
cout << (*root<*n) << endl;
Why does sort never call the operator?? Any help would be appreciated!
Thanks.
madshov
Because you sort the pointer values, not the Nodes they point to.
You can use the third argument of the std::sort algorithm to specify a custom comparator.
For example :
bool comparePtrToNode(Node* a, Node* b) { return (*a < *b); }
std::sort(_children.begin(), _children.end(), comparePtrToNode);
(note that this code is just an indication - you'll have to add extra safety checks where needed)
Your less-than operator takes const Node& arguments, but your vector is sorting Node*s. You need to specify a comparison function as the third parameter to std::sort.
class Node
{
private:
vector <Node*> _children;
string _data;
struct PointerCompare {
bool operator()(const Node* l, const Node* r) {
return *l < *r;
}
};
public:
void add_child(Node* child)
{
sort(_children.begin(), _children.end(), PointerCompare());
}
bool operator<(const Node& node) const
{
return (this->_data.compare(node._data) == -1);
}
};
Also, your operator< needs to be declared const.
Your operator<() operates on references to Node objects; but the vector contains pointers to Node objects, which can't be compared with that function. You'll have to explicitly supply a proper function (one that accepts pointers as arguments) to the sort() algorithm.