custom std::set.find() for a set of pointers - c++

class Node{
public:
Node* back1 = nullptr;
Node* back2 = nullptr;
int value;
Node(int value) {
this->value = value;
}
//bool operator< (const Node& rhs) const {return this->value < rhs.value;}
bool operator< (const Node* rhs) const {return this->value < rhs->value;}
};
std::unordered_map<int, std::set<Node*>> nodes;
void subtractOneOrDouble(int current, int m, Node& prevNode) {
if (current != 0 && current < m && nodes[current % 10].find(current) == nodes[current % 10].end()) {
I have a set of Nodes* and not only do I want to sort them by the value of each node, I want to use find(), input a value, and get the pointer to the node that corresponds to that value. From what I think is going on, find() is taking in pointers, not actual values. What would I need to change so that find() takes in an integer value and gives me the pointer to the Node with that value?

The problem is with the expression
nodes[current % 10].find(current)
The index operator [] of the std::unordered_map will return a std::set (the value of the hash map). Then you apply the find function of the std::set. This set contains "Node*"s. But you are trying to find an int (current). This cannot work.
I am not sure what exactly you want to achieve, but your are searching with the wrong type. You need to give a const Node* as aparameter to the find function.

find takes as input the key type. In your std::unordered_map, that key type is int, and in your std::set that key type is Node*.
If you want to use your elements' sorting, then you can change your std::set's key to be Node instead of Node*. std::set's comparison uses operator < (via std::less) by default, so you can get this working with some tweaks to your code. Here's an example that shows how finding by value can work:
#include <iostream>
#include <set>
struct Node {
int value;
Node(int v):value(v) {}
bool operator <(const Node& rhs) const {
return value < rhs.value;
}
};
int main() {
std::set<Node> nodes;
nodes.emplace(1);
nodes.emplace(2);
nodes.emplace(3);
auto found = nodes.find(Node(2));
if (found != nodes.end()) {
std::cout << "Found node " << found->value << std::endl;
}
else {
std::cout << "Didn't find node!" << std::endl;
}
return 0;
}
This prints:
Found node 2
As it is in your question, your std::set will be sorted by memory address (because that's how Node* is sorted), and not by Node::value.

Related

converting queue to linked list when using operator== c++

I have a queue and a linked list. I am trying to call the operator== function in the linked list through the queue function. The assignment is asking me to compare 2 queues and see if they are the same. I have included the functions from each file that are giving me trouble.
The error message I'm getting is "C2664 'bool List::operator ==(List &)': cannot convert argument 1 from 'const Q' to 'List &'"
queue.h
class Q
{
public:
Q();
Q(const Q &queue);
~Q();
bool operator==(const Q &queue);
private:
List queue;
};
queue.cpp
Q::Q(){}//constuctor
Q::Q(const Q &queue){}//copy constructor
Q::~Q(){}//deconstuctor
bool Q::operator==(const Q &queue1)//this is where the problem is
{
return queue.operator==(queue1);
}
list.h
class List
{
private:
struct Node
{
int data;
Node* next;
Node() : next(NULL) {} //define our own default constructor
Node(int data) : next(NULL), data(data) {}
};
typedef struct Node* NodeRef;
NodeRef head;
NodeRef tail;
NodeRef iterator;
NodeRef current1;
int size;
public:
List();
~List();
List(const List &list);
bool operator==(List &queue);// this is where i have the problem
};
list.cpp
bool List::operator==(List& queue)
{
if (size != queue.size)
return false;
iterator = head;
NodeRef temp = queue.head;
while (iterator != NULL)
{
if (iterator->data != temp->data)
return false;
temp = temp->next;
iterator = iterator->next;
}
return true;
}
main.cpp
Q k,qw;
if (k == qw)
cout << "Lists are equal!\n";
else
cout << "Lists are unequal!\n";
Please help.
You need to compare like for like, in this case a Q only has a queue element (which is actually a List), so when comparing objects of type Q, you need to compare their queue elements.
As you already have an operator == for the List class, so this is straightforward.
bool Q::operator==(const Q &queue1)
{
return queue == queue1.queue;
}
Right, there are a couple of issues here:
return queue.operator==(queue1);
Surely you wanted to use return queue.operator==(queue1.queue); or the shorter return queue == queue1.queue; to compare the internal Queue::List, otherwise, what's the point?
bool operator==(List &queue);
This declaration should become bool operator==(const List &queue); you basically want to use the const whenever you're not changing anything since it allows you to pass both variables and constants to functions. If you don't do it in this case, your code will break since in point 1 you are passing a const.
bool List::operator==(List& queue)
This should become bool List::operator==(const List& queue) since definition should match declaration

No viable conversion from 'Template<int>::Memberclass' to 'const int'

I'm having a problem with return value/reference. I'm writing a template (queue), and Front() function is supposed to return the element from the front of the queue, but I get an error -- No viable conversion from 'Queue<int>::Node' to 'const int'. When I remove const, I get Non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'Queue<int>::Node' instead, and other variations of reference/no reference, const/no const give me either of the two errors. What am I missing?
#include <iostream>
using namespace std;
template <typename T>
class Queue
{
friend ostream& operator<< (ostream &, const Queue<T> & );
private:
class Node
{
friend class Queue<T>;
public:
Node(const T &t): node(t) {next = 0;}
private:
T front;
T back;
T node;
Node *next;
};
Node *front;
Node *back;
public:
Queue() : front(0), back(0) {}
~Queue();
bool Empty()
{
return front == 0;
}
T& Front()
{
if (Empty())
cout << "Очередь пуста." << endl;
else
{
T const & temp = *front; // error here
return temp;
}
}
/* ... */
};
template <class T> ostream& operator<< (ostream &, const Queue<T> & );
int main()
{
Queue<int> *queueInt = new Queue<int>;
for (int i = 0; i<10; i++)
{
queueInt->Push(i);
cout << "Pushed " << i << endl;
}
if (!queueInt->Empty())
{
queueInt->Pop();
cout << "Pop" << endl;
}
queueInt->Front();
return 0;
}
Your Node class definition doesn't make much sense: the way it's now, each node stores 3 data values: front, back and node. Is the class supposed to be a queue of triples?
Nevertheless, in your Front() function, you to need to return the "payload" of the front node (i.e. return something of type T), not the node itself. Something like this:
T& Front()
{
if (Empty())
cout << "Очередь пуста." << endl;
else
{
return front->node;
}
}
Replace
T const & temp = *front;
with
T& temp = front->front;
Queue<T>::front is a pointer to a Node, in other words, *front is a Node. You are trying then to assign a Node to a T& const and, since the compiler cannot convert from Node to T it complains. Now, the Node has a member also called front which is T and I suppose that's what you want to return and that's what the fix does. (Possibly you want to return front->node. Your intent is not clear to me.)
In addition, you declared temp as T const & and Front returns it. However, the type returned by Front is T& (non nonst) and the compiler cannot convert from const to non-const. By declaring temp non-const (as in the fix) such conversion is no longer required.

Sorting of priority_queue elements that are pointer type

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)

Sorting vector of pointers

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.

Implement a map of strings

I have to implement a class that behaves like a map of strings using binary search tree. This is the class I implemented:
template<class T>
class StringMapper {
private:
// Pair
struct Pair {
std::string el1;
T el2;
};
// Nod
struct Node {
Pair* data;
Node* left;
Node* right;
Node()
{
data = new Pair;
}
~Node()
{
delete data;
}
int nod_size()
{
// code here
}
};
Node* root;
public:
StringMapper()
{
root = 0;
}
~StringMapper() {}
void insert(std::string from, const T& to)
{
// code here
}
bool find(std::string from,const T& to) const
{
return find(root, to);
}
bool find(Node* node, const T& value) const
{
// code here
}
bool getFirstPair(std::string& from, T& to)
{
if(root != 0)
{
from = root->data->el1;
to = root->data->el2;
return true;
}
return false;
}
bool getNextPair(std::string& from, T& to)
{
if(root != 0)
{
}
return false;
}
int size() const
{
return root->nod_size();
}
};
To be honest I don't know how to implement the function getNextPair().
If someone could help me I'd appreciate it.
Your interface is an internal iterator. You need to keep some kind of pointer to where you are in the iteration, and set it in getFirstPair().
Once you add this, getNextPair() just goes to the next one. It's somewhat difficult to do this, but that's your assignment, so I leave it to you.
The actual std::map uses an external iterator -- that keeps the state of the iteration separate from the data structure. The major advantage is being able to have more than one simultaneous iteration.
Without just throwing the algorithm for getNextPair, you will need to keep some kind of internal iterator which will point to the "current" pair. Once you got that, in order to figure the algorithm for the next pair draw yourself a tree with some nodes and see how one can find the next node in the tree given any node in the tree.