Sorting in C++ using defined class - c++

I'm kind of new at C++, so bear with me if you can. I'm trying to sort a vector full of nodes. In my .h file I have the following definition for a node:
class Node{
public:
Node(int data);
bool sortMe(const Node & n1, const Node & n2);
int getData();
private:
int nData;
};
In my .cpp file, I define the functions such as:
Node::Node(int data){
this->nData = data;
}
bool Node::sortMe(const Node & n1, const Node & n2){
return n1.nData < n2.nData;
}
and in main attempt to sort a vector with:
Node aNode(7);
Node bNode(90);
Node cNode(84);
std::vector<Node> arrayName;
arrayName.push_back(aNode);
arrayName.push_back(bNode);
arrayName.insert(arrayName.begin(), cNode);
std::sort(arrayName.begin(), arrayName.end(), &Node::sortMe);
I include algorithm and everything, I just can't figure out why it doesn't want to use that function to sort the data...
Thanks in advance!

sortMe() is currently declared as a member function. That means it needs to be called on a specific instance of the Node class, rather than being used as a standalone function.
To fix it, simply prefix the function declaration with static (only in the class header; not in the implementation). That means the function belongs to the class, not a specific instance.

You can use boost::bind:
std::sort( arrayName.begin(), arrayName.end(),
boost::bind(&Node::sortMe, this,_1,_2));
or make sortMe function static.
Even better is to use a functor instead of a function (this will be faster):
class Node{
public:
Node(int data);
bool sortMe(const Node & n1, const Node & n2);
int getData();
struct doCompare
{
bool operator()( const Node& n1, const Node& n2 )
{
// comparison code
}
};
private:
int nData;
};
std::sort( arrayName.begin(), arrayName.end(), Node::doCompare() );

The std::sort() need a reference of comparison function.
There will be two ways to implement the comparison function:
static member function
A normal member function shall not be used since a member function must need a specific instance of its class.
class Node{
public:
static bool sortMe(const Node & n1, const Node & n2);
};
normal function().
Remove the 'bool sortMe(const Node & n1, const Node & n2);' out from the Node class to the main.cpp, the problem will be solved.
bool Node::sortMe(const Node & n1, const Node & n2){
return n1.nData < n2.nData;
}

If you use C++11, you can use lambda.
std::sort(arrayName.begin(), arrayName.end(), [](Node& l, Node& r){ return l.getData() < r.getData(); });

Related

boost::fibonacci_heap: Nested define of handle with comparator redefined circular definition errors

Boost documentation and previous stack overflow both give working examples of how to define custom comparator functions and include handle in the node type of a boost heap. However when I combine both of these features (a custom defined compare function and a handle within the node type) I get errors reporting invalid use of incomplete type of 'struct compare_Node'.
https://www.boost.org/doc/libs/1_63_0/doc/html/heap/concepts.html#heap.concepts.mutability
Using boost fibonacci_heap
Defining compare function for fibonacci heap in boost
Decrease operation in fibonacci heap, boost
Other than predefining both structs of Node and compare_Node I'm not sure to solve the circularity while still holding the handle's safely as a member within the Node struct.
#include <boost/heap/fibonacci_heap.hpp>
struct compare_Node; //predefine to avoid circular issues
struct Node; //predefine to avoid circular issues
using fib_heap = boost::heap::fibonacci_heap<struct Node*,
boost::heap::compare<struct compare_Node>>;
// 6-byte struct total
struct Node {
double value;
fib_heap::handle_type* handle; // orig
};
// override for min_heap
struct compare_Node
{
bool operator() (struct Node* const n1, struct Node* const n2) const
{
return n1->value > n2->value;
}
};
int main() {
fib_heap heap;
return 0;
}
Define compare_Node only with the declaration of operator(). Pointers to Node don't need Node definition. After Node definition, you can add the body of operator():
struct compare_Node
{
bool operator() (struct Node* const n1, struct Node* const n2) const;
};
using fib_heap = boost::heap::fibonacci_heap<struct Node*,
boost::heap::compare<struct compare_Node>>;
// 6-byte struct total
struct Node {
double value;
fib_heap::handle_type* handle; // orig
};
bool compare_Node::operator() (struct Node* const n1, struct Node* const n2) const
{
return n1->value > n2->value;
}
Online demo.

Return value type does not match the function type CONST

Not sure why error is happening on this function when I made the variable length const on a different function
int list::length() const {
return length;
}
CPP File Above
Header file BELOW
class list {
private:
struct Node
{
int info;
Node *next;
};
int length;
Node *head;
public:
list();
list(const list& otherlist);
~list();
int list::length() const;
};
The first issue is that you are qualifying length() inside your class. Remove list::. The second issue is that your member variable length, and your member function length are conflicting, because they have the same name.
I'd rename your members so that they don't clash with the functions. Consider length_ and head_.
Edit: please also post compiler errors in the future, as it makes other readers' jobs a little easier :)

How to have this const-corrected?

I have a const-correctness problem which I don't seem to be able to resolve. Here is the structure of my program:
class Node
{
private:
int id;
std::set<Node*> neighbours;
public:
Node();
Node(int id_p);
void set_id(const int& id_p);
int get_id() const;
void add_neighbour(Node* neighbour);
bool is_neighbour(Node* neighbour) const;
friend bool operator <(const Node& lhs, const Node& rhs);
};
class Graph
{
private:
std::set<Node> node_list;
public:
Graph();
void add_node(int id);
const Node* get_node_by_id(int id) const;
bool has_node(int id) const;
void check_add_node(int id);
void add_edge(int id_1, int id_2);
bool has_edge(int id_1, int id_2) const;
void check_add_edge(int id_1, int id_2);
(...)
};
Now the thing is, if I call the function Graph::get_node_by_id(), I want to return a pointer to a given node (type Node). But it seems impossible to do so, because the std::set implicitly converts my Node type objects to const Node objects, and I am unable fetch a non-const pointer from a const object.
However, I cannot have everything else set to const Node (which would resolve the problem), because I want to call Node::add_neighbour() from Graph::add_edge(), but whenever I do so, my compiler says that I might be violating the constness (required to have a sorted set) of the elements in the node_list set, even though I defined the less operator< to only care about the id.
Is there anything I can do to resolve this dilemma (without giving up on having a sorted set)? Thank you for your responses!
More info on the error:
If I use non-constant fields, error in Graph::get_node_by_id():
for(Node& element : this->node_list) // Error: element should be const Node&
{
if(element->get_id() == id)
{
return element;
}
}
return nullptr;
If I use constant fields, error in Graph::add_edge():
(...)
const Node* node_1 = this->get_node_by_id(id_1);
const Node* node_2 = this->get_node_by_id(id_2);
node_1->add_neighbour(node_2); // Error for disregarding constness
node_2->add_neighbour(node_1);
Your issue appears to be that you have two different 'value semantics' to Node.
One is that exposed by operator< which is not affected by add_neighbour. This is the one set needs, to keep things ordered, and which it enforces by making Node const.
The other is that exposed by the class API, where both set_id and add_neighbour would change the value.
To keep your sorted set, you must not allow the id of a node to change once it's in the set. But you can allow the neighbours to change.
So I'd suggest you make the neighbours set mutable, make add_neighbour private and const, and make Graph a friend of Node.
This is what mutable gives you, data members that are not part of the 'value' of a type. Note that this means you are indicating that something holding a const Node* may expect the result of is_neighbour to change between calls.
So...
class Node
{
private:
// Trust Graph not to mess directly with these!
int id;
mutable std::set<Node*> neighbours;
friend class Graph;
// For Graph's exclusive use
void add_neighbour(Node* neighbour) const;
public:
Node();
Node(int id_p);
void set_id(const int& id_p); // Callable when not in Graph's set
int get_id() const;
void add_neighbour(Node* neighbour); // Callable when not in Graph's set
bool is_neighbour(Node* neighbour) const;
friend bool operator <(const Node& lhs, const Node& rhs);
};
class Graph
{
private:
std::set<Node> node_list;
public:
Graph();
void add_node(int id);
const Node* get_node_by_id(int id) const;
bool has_node(int id) const;
void check_add_node(int id);
void add_edge(int id_1, int id_2);
bool has_edge(int id_1, int id_2) const;
void check_add_edge(int id_1, int id_2);
(...)
};
Now what you have is public, non-const mutators for Node instances that aren't in Graph's set, and an extra mutator for Graph to use to change the neighbours of the Nodes in its set.
So only Graph can do
const Node b;
b.add_neighbour(nullptr);
If you really don't trust Graph, you can replace the private const add_neighbour with an inner class, with a static add_neighbour(Node* node, Node* neighbour method, since an inner class is implicitly able to access private data of the outer class.
class NeighbourHelper {
friend class Graph;
static void add(const Node* node, Node* neighbour) {
node->add_neighbour(neighbour);
}
Now only Graph can do
const Node b;
Node::NeighbourHelper::add(&b, nullptr);
In both cases, the following works for everyone:
Node a;
a.add_neighbour(nullptr);
At this point, you should be suffering a code-smell... The issue is the public get_node_by_id method in Graph. You actually probably want to expose an iterator of some kind instead, rather than than the raw Node*, and make Node a private inner class of Graph.
Or even just replace the whole Node concept with std::map<int,std::set<int>>...
But it depends on your actual use case.
Although TBBle's analysis is correct, there's a much simpler solution: replace Graph's std::set<Node> with std::map<int,Node>.
Your current Graph::get_node_by_id() is using a linear search because set doesn't really provide the lookup you want. Making the key external allows you to remove the operator< overload and still get a faster and more natural lookup: map.find(id).
The only ugly part is that now your Node has an internal id which must match an external key. If you never use the id except to look up a node in the map, you could just remove this entirely. If you need to follow the graph edges (neighbours) and then check the ID, you can replace your set of pointers with a set of map iterators, like:
typedef std::map<int, Node> NodeMap;
typedef std::set<NodeMap::iterator> NeighbourMap;
Then your traversal has the pair<const int,Node> available.
NB. on reflection, changing from set to map produces almost the same distinction as TBBle's answer: you split the Node into const and mutable parts. The lookup is cleaner with this solution (you can regain logarithmic-time lookup by constructing a fake Node as a key for set::find, but it's still a little inelegant), and the object identity is slightly cleaner with the other solution.

What is wrong in the function declaration?

Explain to me, please, in what a mistake in the declaration/description of this method?
class Set
{
struct Node {
// ...
};
// ...
Node* &_getLink(const Node *const&, int) const;
// ...
};
Node* &Set::_getLink(const Node *const &root, int t) const
{
// ...
}
I don't see mistakes, but the compiler (MS VS C++) gives out many syntax errors.
You forgot to fully qualify the name of Node (which is defined in the scope of Set):
Set::Node* &Set::_getLink(const Node *const &root, int t) const
// ^^^^^
Without the fully qualification, the compiler will look for a global type named Node, which does not exist.
The problem is a scoping one. You need to prefix Node here:
Set::Node* &Set::_getLink(const Node *const &root, int t) const
{
// ...
}
Indeed, Node is unknown at the time it is encountered (you are at namespace scope, not inside Set's scope). You can also use auto:
auto Set::_getLink(const Node *const &root, int t) const -> Node *&
{
// ...
}
After ->, you are at Set's scope and Node is known.
you dont define Node in global scope
so use this code
//by Set::Node we give compiler that this function exist in class Node
Set::Node* &Set::_getLink(const Node *const &root, int t) const
{
// ...
}

Returning a pointer using get method from class and using *& to take it in recursively

So I am just working on some code and have kind of stumped myself
I have a class Node and another class BinaryTree:
class Node
{
public:
Node();
Node(int thedata, Node* right, Node* left):data(thedata), right_pointer(right), left_pointer(left){};
int get_data(){return data;}
Node* get_right() {return right_pointer;}
Node* get_left() {return left_pointer;}
private:
int data;
Node* right_pointer;
Node* left_pointer;
};
class BinaryTree
{
private:
Node* root;
void add_tree_node(Node*& root,int data);
void print_tree(Node* root);
public:
BinaryTree();
void print_tree();
void add_tree_node(int data);
};
My issue is with this command:
add_tree_node(root->get_right(), data);
I get an error saying: no instance of overloaded function.
which get_right() returns a pointer to the pointer and was wondering if there was a better way of doing this instead of the two options below.
when I do this:
Node* right = root->get_right();
add_tree_node(right, data);
or
add_tree_node(root->right_link,data);
it works and I understand why it works because we are passing in the pointer itself and not the value.
Node* &get_right() {return right_pointer;}
Node* &get_left() {return left_pointer;}
node->get_right() returns an rvalue. add_tree_node() takes a non-const reference. You can only make a non-const reference out of an lvalue, not an rvalue. Therefore the return value of node->get_right() cannot be turned into a non-const reference unless you put it into a local variable first.
That said, why does add_tree_node() take a reference to begin with? It's already taking a pointer, so you can mutate the Node all you want without needing a reference.
Sounds to me like you need an insert( & node, data) function
then in your main, you can create a new binary tree with your constructor with something like this: Node binaryTree = new Node();
from there, you can insert nodes like this: binaryTree->insert( binaryTree, data );