STL set find performance - c++

How to overwrite operator() inside of class MyNode so that set::find can use, and a sets that stores MyNode*. Then I try to find pointer in set, whose data field is the same as in given object. The below code does not work as I expected. I set breakpoints in of operator method, but none stopped.
I understand I can define find struct compare{} outside of class MyNode, and then define sets like:
set sets
This is oK for me. Here I am wondering whether it is possible I can define compare inside of class MyNode.
My code is like:
class MyNode {
std::string data;
public:
MyNode();
MyNode(std::string str);
MyNode(const MyNode& orig);
virtual ~MyNode();
std::string getData();
bool operator<(const MyNode& node){
return data<node.data;
}
bool operator<( const MyNode* node){
return data<node->data;
}
};
void testset(){
MyNode* node1 = new MyNode("5S");
MyNode* node2 = new MyNode("AH");
MyNode* node3 = new MyNode("AH");
std::cout<<" "<<node2<<std::endl;
std::set<MyNode*> sets;
sets.insert(node1);
sets.insert(node2);
std::set<MyNode*>::iterator iter =sets.find(node3); // I expected node2 can be found, but it does not..
if(iter != sets.end()){
MyNode* no = *iter;
std::cout<<"find it "<<no<<std::endl;
}
}
Another question is if I only define set like:
set<MyNode> sets.
std::find(sets.begin(), sets.end(), findmethod("aa"))
Is this complexity O(N) or O(log N)?

As for the first question: std::set doesn't care about operator()(); it cares about operator<().
As for your second question: the std::find algorithm, unlike the std::set<T>::find method, is O(n).

Related

Avoid infinite recursion in destructor

As part of an exercise my university has tasked me with, I have written a small Graph implementation, following this header.
class Node {
private:
std::string name;
std::vector<Node*> children;
public:
Node(const std::string& name="");
virtual ~Node();
}
When writing code for the destructor ~Node(), I noticed that my implementation fails when the graph contains a cycle. This is my implementation so far, which obviously doesn't work if the graph contains a cycle.
Node::~Node() {
for (Node* n : children) {
delete n;
n = NULL;
}
children.clear();
}
I am uncertain as to how I would most elegantly write a destructor that can handle cycles in the graph?
Please note that I was specifically tasked to write a recursive destructor.
Thank you for your answers!
Option 1: Choose a representation for the graph where nodes are not owned by other nodes, but rather the graph which would be a distinct object. This way the node destructor doesn't need to do anything. This won't satisfy the requirement of recursion:
struct Graph {
std::vector<std::unique_ptr<Node>> nodes;
};
Note that if there is no inheritance involved, then you could simply use std::vector<Node>. I assume that there is, due to the usage of virtual desturctor in Node.
Alternatively, you could use another representation for the graph such as adjacency list.
Option 2: Use an algorithm to generate a minimum spanning forest of the graph. Then recursively delete the roots of each spanning tree. You can for example use the Kruskal's algorithm. (Given your representation, it looks like your graph may be connected, in which case there would be only one spaning tree).
One option could be to first create an unordered_set of all the Node*s and then to delete them.
void fill(std::unordered_set<Node*>& to_delete, Node* ptr) {
// try to insert ptr and return if it was already in the set
if(not to_delete.emplace(ptr).second) return;
// swap ptr->children with an empty vector
std::vector<Node*> tmp;
std::swap(tmp, ptr->children);
for(Node* c : tmp) // loop over the pointers
fill(to_delete, c); // fill recursively
}
virtual ~Node() noexcept { // std::terminate if anything should throw
if(children.empty()) return; // nothing to do here
std::unordered_set<Node*> to_delete; // to collect all the Node*'s
fill(to_delete, this); // fill the set recursively
to_delete.erase(this); // don't delete "this"
for(auto c : to_delete) // delete all - they have no children by now
delete c;
}
Demo
If your graph is a tree (I assume it since your implementation of destructor is valid only for a tree) and you can store parent of the Node then you can write iterative version which do not require any extra data structure to avoid recursion.
Also learn to use smart pointers.
class Node {
private:
std::string name;
std::vector<std::unique_ptr<Node>> children;
Node* parent;
void safeCleanClildren();
public:
Node(std::string name="", Node* parent = nullptr)
: name{std::move(name)}
{}
~Node() {
iterativeCleanClildren();
}
void addChild(std::string name) {
children.emplace_back(std::make_unique<Node>(std::move(node), this);
}
};
void Node::iterativeCleanClildren()
{
auto p = this;
while (!p->children.empty()) {
while (!p->children.empty()) {
p = p->back().get(); // go as deep as possible
}
if (p != this) {
p = p->parent; // go back to parent
p->children.pop_back();
}
}
}
How this work?
first it finds leaf (right most) in a tree (node which do not have children)
Then goes back to parent node and remove child which was just found p->children.pop_back(); (this destroys unique_ptr of just found leaf).
Then finds again leaf and so on.
This tree clearing continues until root (this) node is reached
This way root node ends with no children at all and since it is iterative implementation overflown is impossible. It doesn't matter how much unbalance this tree is.

How to get all "next" nodes in a linked list? Building a call string does not work

So I have a problem. My objective is to iterate through sigly linked list I've created. I want to use std::string as an argument to if statement like listed below. I know it's not a good idea, even more: I know it may be the WORST possible way to do this. It doesn't matter I want to know if it can be done.
I tried using macro function but either I'm doing it wrong or it's not possible using such macro. Help me please. I'm out of ideas...
Similar macros I used in my old project where I've passed as parameter a name of function (user typed the name of such function like 'sin' or 'tan') from cmath lib to calculate integral for given function, so I thought it would work in this case as well but apparently not. It says:
conditional expression of type 'std::string' is illegal
//structures.h
struct node
{
int _value;
node *pNext;
};
//functions.cpp
#define retarded_at(x) x
#define retarded_stringify(y) retarded_at(y)
//#param pHead pointer to first element of the list
void retDispIter(node *pHead)
{
std::string at{ "pHead->pNext" };
while (retarded_at(at))
{
at += "->pNext";
//here send node->_value to std::cout
}
}
Inside first while loop "at" would be 'pHead->pNext' poining at next element. With 8 elements in the list the last while would be like:
while(pHead->pNext->pNext->pNext->pNext->pNext->pNext->pNext->pNext)
return false and "at" would contain a 'pointer' (nullptr) to the non-existing 9th element.
What You want to acheive is not possible in the way that You are requesting:
C++ cannot execute "text" created at runtime, all code has to be available at compile time, so it can be compiled into the target machines - machine code,
during runtime, symbols (names of variables, classes, functions, ...) are not used by the machine code (Symbols are converted to addresses and registers and address offsets)
The simplest way to get this to work is:
//#param pHead pointer to first element of the list
void retDispIter(node *pHead)
{
node* current_node = pHead;
while (current_node)
{
//here send current_node->_value to std::cout
current_node = current_node->pNext;
}
}
Another way is to make a very simple iterator class;
struct node_iterator
{
node* current;
node_iterator operator++()
{
node* temp = current;
current = current->pNext;
return node_iterator { temp };
}
node_iterator& operator++(int)
{
current = current->pNext;
return *this;
}
node* operator->() const { return current; }
node& operator*() const { return *current; }
explicit operator bool() const { return current != nullptr; }
bool operator==(const node_iterator& other) const { return current == other.current; }
bool operator!=(const node_iterator& other) const { return !(*this == other); }
};
Then it can be used like this:
//#param pHead pointer to first element of the list
void retDispIter(node* pHead)
{
node_iterator iter { pHead };
while (iter)
{
// usage
std::cout << iter->_value;
std::cout << (*iter)._value;
// get next
++iter;
}
}
C++ is not like matlab or python. It won't compile strings or lines of code in run-time. So no, you cannot use strings this way.
Check out the differences by googling "compiler vs interpreter". C++ is compiler based while python is interprer based. Users of C++ generated programs do not need to have all the build tools to run them.

c++ overloading [] to print nth item of linked list

I have an assignment which involves different linked list operations. One of them involves overloading the square bracket operator to be able to print the ith element of the linked list. I have everything else done but I am really lost on this. This is what I am working with. The list class is as follows:
class List {
public:
// Creates a default empty list
List();
// Simple destructor
~List();
// Insert "data" at the very end of the list
void AddToFront(int data);
// Remove and return the first data item from the list.
int deleteFront();
// Prints the list
void Print() ;
// Returns the size of the list
unsigned int Size() const;
//overloaded assignment operator
Node operator[](unsigned int i) ;
private:
Node *m_head;
};
Also, here is my node class:
class Node {
public:
Node();
~Node();
Node(int data);
int m_data;
Node *m_next;
};
Any help on the overloading [] operator would be greatly appreciated.
Node* operator [] (int value) {
Node *temp = this->m_head;
for(int i = 0; i < value && temp!=NULL; i++) {
temp = temp->m_next;
}
return temp;
}
I assume that you want to return the node corresponding to the value specified, in the square brackets. You overload any operator using the operator keyword followed by the operator, and then the parameters passed.
For more info check this :: Operator overloading
EDIT ::
As pointed by erip and Lajos there should be a way, in case the (value > size_of_list), in that case, a possible solution would be throw an exception, which you can later catch in your program to show that value was out of bound. Or considering the current implementation, if value > size_of_list in that case temp would become NULL, so during your execution you can check if value of Node * returned is NULL or not.
A further more optimized way would be to keep a variable size_of_list in the class List, and then we can simply add an if condition to the function like this ::
if(value >= size_of_list) // equal to sign is put, considering your `size_of_list` starts from 1
return NULL;
This, would be more optimized in case of large Lists, which would avoid wasteful execution of the for loop!

c++ store items into an array

I have this code that in my mind, it recieved an item called Vehicle and it has to store it in an array called Node. This is the code related to this part of the program:
void Table::process(Vehicle v, int cont) {
char a='A'+cont;
putVehicle(a,v);
Node.a_v[cont]=v;
if(cont==0) a_surt=v.rowVehicle();
}
This is how I have the array on the private part of Table.h:
struct Node{
Vehicle a_v;
};
The error I get is:
error: expected primary-expression before '.' token
I have the includes I need, but everytime I type this: Node.a_v It gives me that error.
Any advice?
If you want to use a struct, you need to declare a Node before using it. Also, the struct needs to contain an array (or better, look into vectors for more flexibility).
struct Node {
Vehicle[10] a_v; // 10 is max number of Vehicles in array
};
Node myNode;
myNode.a_v[cont] = v;
Remember that if you want to keep this Node around and put more things in it, it needs to be declared in the right scope. For example, to have your process function add a Vehicle to a Node that exists outside of the function process, you could something like this:
void Table::process(Node n, Vehicle v, int cont) {
char a = 'A'+cont;
putVehicle(a,v);
if (cont < 10) {
n.a_v[cont] = v;
}
if (cont == 0) a_surt = v.rowVehicle();
}
It kind of looks like you're just trying to use an array. In that case you're looking for something like this:
// This would go somewhere in your program. Again, 10 is just an example.
Vehicle vehicleArray[10];
// Send this array to this function
void Table::process(Vehicle[] vArray, Vehicle v, int cont) {
char a = 'A'+cont;
putVehicle(a,v);
if (cont < 10) { // In a real program, don't hard-code array limits.
vArray[cont] = v;
}
if (cont == 0) a_surt = v.rowVehicle();
}
You should use Node object to get access to the a_v variable. This line
Node.a_v[cont]=v;
Is incorrect. You should do something like that:
Node n;
n.a_v[cont]=v;
everytime I type this: Node.a_v It gives me that error.
Node is a type; types define the structure of a objects, but they do not have fields of their own (except the static fields, which belong to all instances at once; they are accessed differently anyway).
In order to use a . or -> operator, you need an instance of a Node, like this:
Node x;
x.a_v = ...
It is not clear in your case from where the Node instances should be coming, though. In order to access them, you would need to either pass them in as parameters, or make them available statically/globally (not recommended).
Okay, so Node is NOT the name of your array. It's the name of a user-defined type that is supposed to contain an array. Your Node, however, does not contain an array. It contains one Vehicle, named a_v. I assume a_v is supposed to represent an Array of Vehicles. Therefore, you need to allocate the array. Something like this:
struct Node {
Vehicle a_v[AMOUNT];
};
If you don't know at compile-time how large you want your arrays to be, then they must be dynamically allocated, like this:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
};
If it's dynamically allocated, then it must also be deallocated:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
~Node() {
delete[] a_v;
}
};
AND if it's dynamically allocated, you need to add provisions for copying or disable copying:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
~Node() {
delete[] a_v;
}
// Disable copies (with C++11 support):
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// Disable copies (without C++11 support) by making them private and not defining them.
private:
Node(const Node&);
Node& operator=(const Node&);
};
Then to access one of the Vehicles, you'd need to do so like this:
Node n; // Declare a node, which contains an array of Vehicles
n.a_v[cont] = v; // Copy a Vehicle into the array of Vehicles
Note, however, that if you declare the Node instance in this function, then it is local and it will go out of scope as soon as your function ends. You need to declare the Node instance as a member of your Table if you want it to persist past the function call.
class Table
{
private:
Node n;
};
Lastly, as others have suggested, I'd highly recommend that you read a C++ book to learn C++. My personal recommendation is this book (5th edition, don't buy 6th or 7th - the author of those editions is terrible).

Traversing a non-STL linked-list in C++, possible?

Let's say I'm using a non-standard linked-list class, List.h. This class is functioning, template'd and has the typical features of add/remove to front and add/remove to back, isEmpty(), etc.
This list does not have any begin() and end() functionality. Also, does a linked-list class have to include iterator functionality? Or is that something I can create on my own when I create a new List?
I'm used to working with STL, so I would usually use this code:
typedef vector<OBJECT>::iterator QuoteIt;
for(QuoteIt i = deposits.begin(); i != deposits.end(); ++i)
Anyway, lets say I create a new "List".
List<int>deposits;
or even a List of Objects
List<OBJECT>deposits;
So let's say I addToBack() 20 different integers, so that creates the appropriate # of new nodes.
Now, how can I traverse this list so I can find a sum of all these ints? Is that possible, or does my current functionality prevent that? I would have to implement some sort of iterator to my List Class?
Now I know I could keep an outside variable, every time I do an addToBack() call to keep track of my sums. However, I want the code to be compatible with Lists of Objects as well. (I want to be able to search one value in a node, and retrieve another value in the same node eventually)
I'm so used to working with stl::list and creating a for loop with iterators, I really dont' know how to get this working with other classes.
btw here is the code for List():
template<class NODETYPE>
class List{
public:
List();
~List();
void insertAtFront(const NODETYPE &);
void insertAtBack(const NODETYPE &);
bool removeFromFront( NODETYPE &);
bool removeFromBack( NODETYPE &);
bool isEmpty() const;
private:
ListNode< NODETYPE > *firstPtr; //pointer to first node
ListNode< NODETYPE > *lastPtr;
//Function to allocate a new node
ListNode< NODETYPE > *getNewNode ( const NODETYPE &);
};
//default constructor
template <class NODETYPE>
List< NODETYPE > ::List()
: firstPtr(0),
lastPtr(0)
{
cout<<"Creating Nodes! \n\n!"<<endl;
}
//deconstructor
template <class NODETYPE>
List<NODETYPE>::~List(){
if(!isEmpty() ){
cout<<"Destroying nodes!"<<endl;
ListNode<NODETYPE> *currentPtr=firstPtr;
ListNode<NODETYPE> *tempPtr;
while( currentPtr !=0){
tempPtr = currentPtr;
currentPtr=currentPtr->nextPtr;
delete tempPtr;
}
}
cout<<"All nodes destroyed! \n\n";
}
template <class NODETYPE>
bool List <NODETYPE>::removeFromFront( NODETYPE & value){
if ( isEmpty() )
return false;
else{
ListNode<NODETYPE> *tempPtr = firstPtr;
if (firstPtr== lastPtr)
firstPtr=lastPtr = 0;
else
firstPtr=firstPtr->nextPtr;
value = tempPtr->data;
delete tempPtr;
return true;
}
}
template <class NODETYPE>
bool List<NODETYPE>::removeFromBack(NODETYPE &value)
{
if (isEmpty())
return false;
else{
ListNode< NODETYPE> *tempPtr = lastPtr;
if( firstPtr == lastPtr)
firstPtr = lastPtr = 0;
else{
ListNode<NODETYPE> *currentPtr=firstPtr;
//Finds second to last element
while(currentPtr->nextPtr !=lastPtr)
currentPtr=currentPtr->nextPtr;
lastPtr = currentPtr;
currentPtr->nextPtr=0;
}
value = tempPtr->data;
delete tempPtr;
return true;
}
}
//Checks to see if list is empty
template< class NODETYPE>
bool List< NODETYPE >::isEmpty() const{
return firstPtr == 0;
}
//returns a pointer to newly created Node
template<class NODETYPE>
ListNode<NODETYPE> *List<NODETYPE>::getNewNode(const NODETYPE &value){
return new ListNode<NODETYPE>(value);
}
In response to:
Now, how can I traverse this list so I can find a sum of all these ints? Is that possible, or does my current functionality prevent that? I would have to implement some sort of iterator to my List Class?
You need to implement a way to iterate over your list that does not (as a side-effect) destroy your list.
In response to:
Now, how can I traverse this list so I
can find a sum of all these ints? Is
that possible, or does my current
functionality prevent that? I would
have to implement some sort of
iterator to my List Class?
No matter how you design a linked list, you must have some sort of pointer to the beginning of the list, and you have to have a way of knowing when you are at the end (e.g. when "next" is null, or by having a pointer to the end). By exposing those data one way or another, you can always set up a list traversal:
Start at the beginning. (In your case, get a hold of firstPtr.)
If you are not at the end, move to the next element. (In your case, get ->nextPtr.)
Using that pattern to accumulate a value as you visit each element you should be able to handle your task with ease.
If your list does not give you public access to its beginning, then it is certainly not a general-purpose list!
You can approach this many ways. You can either choose to create your own iterator or give public access to the list's head.
Option 1 is compatible with stl lists so you might want to go that route. An iterator is essentially a ptr that overrides the inc and dec operators to go to the next or previous position in the list.
If you studied basic data structures at all, you would know that traversing a list is trivial.
Node<type> t = head;
while (t != NULL)
{
// process node here
t = t->next;
}
The code can differ depending on if you use dummy nodes at all.
Since there is no functionality to just get the node without removing it from the list, you can't simply make an "add-on" iterator without changing the List class. The least you would need to do is to either
friend the external ListIterator class
friend free begin and end functions
add begin and end functions to the List class
Without any of those three, you can't achieve what you want.
Your list seems to have 2 ways of iterating it (forwards and backwards)
List<int>deposits;
.. add stuff:
int o;
int sum = 0;
while(deposits.removeFromFront(o)) {
sum+=o;
}
The bad thing though, is that iterating it, you also destroy the list,
you could provide public accessors to List::firstPtr and ListNode::nextPtr in which case you could do:
List<int>deposits;
.. add stuff:
int sum = 0;
for(ListNode<int> *ptr = deposits.firstPtr; ptr ; ptr = ptr->nextPtr)
sum+=ptr->data;
However, use an existing STL container if you can.