I need help creating a non-binary tree structure. This structure must contain a class node with as many pointers to node as a the node needs. This is where I get confused.
Here is my class node:
class nodo{
public:
int id;
char info[255];
nodo **son,*father;
nodo()
{
strcpy(info,"");
son=(nodo*)malloc(sizeof(nodo));
}
};
As far as I understand, each time I need a new son pointer I must do the following code:
son=(nodo*)realloc(sizeof(nodo)*t)
t being the number of nodes I want to add plus 1. I canĀ“t seem to understand how to access the pointers. For example, I've already added 2 sons and I want to access the second one, how should I do it?
Is there any other approach to the problem?
Any help will be thanked.
You're writing C++, not C. Don't try to re-implement your own dynamic array from the ground up. The standard library already has std::vector to handle that for you.
class nodo{
public:
int id;
std::string info;
nodo *parent;
std:::vector<nodo *> children;
nodo(nodo *parent) : parent(parent)
{
}
void add_child(nodo *child) { children.push_back(child); }
};
You're trying to dynamically create an array of child pointers for each node. This approach is fine as long as you know how many children the node will have beforehand.
Your constructor should look something like this:
nodo(int numsons) {
son = new nodo*[numsons];
}
This will allocate an array of child nodes, which you will need to delete in the deconstructor.
If you don't know how many children the node will have beforehand (when you call the constructor), you should use a vector.
Related
I was trying to store the class object in a file but as the class contains a vector of pointers which is causing a trouble because next time I am accessing the class I am able to fetch everything but this vector.
typedef vector<pair<int, MBR *>> vppint;
class Node{
private:
int id;
int parentID;
int total_children;
MBR *mbr;
vppint children;
public:
vppint fetchChildren(){
return return this->children;
}
int totalChildren(){
return this->total_children;
}
};
MBR is some class.
after storing this Node class in the file and then reading it. the fetchChildren function throws segmentation fault with the obvious reason. is there any way to store the object and not just the pointer.
In C++ you can work with Constructors and Destructors if you would want to create / destroy an instance of a class (I believe those are not needed but it could help you understand how it works).
You can do so by declaring a public constructor in your node class. And then declare the function. Node::Node() {} which in our case will be empty.
class Node{
private:
int id;
int parentID;
int total_children;
MBR *mbr;
vppint children;
public:
Node();
vppint fetchChildren(){
return return this->children;
}
int totalChildren(){
return this->total_children;
}
};
When you have a constructor which will initialize values (or if you prefer to not use a constructor) you can simply store the class object alike:
Node savedObject = Node(); // Creates an instance of the Node class.
If this is what you want to achieve I would suggest you read something as: https://www.w3schools.com/cpp/cpp_constructors.asp for more information.
That's C++. Until now you have to write your own serialization logic which handles pointers correctly. You can take a look at boost::serialization, what provides a lot of helper functions. Note that boost::serialization makes your serialization tool output platform dependet. If you want crossplatform serialization, you have to either put some more effort into your seriaization logic or make use of something like protobuf.
I have struct Node and struct UniqueInstructor. Both are singly-linked lists. I have already filled struct Node with some values. Now what I need to do is fill the second UniqueInstructor struct with Node's struct specific value (std::string instructor).
This is how my structs look like:
// main struct that I already filled with data
struct Node {
Node* pNext;
std::string data1;
std::string data2;
std::string day;
std::string group;
std::string instructor; // these are the items I want to copy
// into the UniqueInstructor struct
std::string course;
};
// my 'target' struct, also linked list
struct UniqueInstructor {
UniqueInstructor* pNext;
std::string instructor;
};
For now, all I need to do is copy all the std::string instructor values from Node into UniqueInstructor.
I have tried bunch of things, such as:
void DuplicateInstructor(Node *&pHead)
{
pHead = new UniqueInstructor { pHead, pHead->instructor };
}
but I am getting errors. In this case:
cannot convert 'Node*' to 'UniqueInstructor*' in initialization
My problem probably lies somewhere in passing struct into that function. Please be forgiving, I am fresh-new to structs and pointers. Thank you for help.
You just need to copy the Node::instructor field into the UniqueInstructor::instructor field. Both fields are std::string so that is no problem.
void like_this(Node& n, UniqueInstructor& i)
{
i.instructor = n.instructor;
}
Now it's not very clear what you actually trying to achieve and what your program structure is so I can't tell you where or how you get the Instructor object. In the example above both objects exist. Also you can't link a Node with an UniqueInstructor. Simply Node::pNext and UniqueInstructor::pNext are of completely different types, so I don't know what you are trying to do here.
Moreover explicit new / delete calls are a very bad practice. They have absolutely no place in C++ (outside of library implementations). Too much headache and more importantly too much room for bugs (memory leaks on exceptions). Please read about RAII and smart pointers in C++.
I'm trying to create a node class that contains a vector of pointers. Here's my code:
node.h:
#ifndef NODE_H
#define NODE_H
class node
{
public:
vector<node*> next;
void add_arc(node & a)
string some_string;
#endif
node.cpp:
void node::add_arc(node & a)
{
node *b = &a;
next.push_back(b); //only copyies nodes
}
main.cpp:
int main()
{
vector<node> nodes;
node a;
node b;
node c;
a.somestring = "a";
b.somestring = "b";
c.somestring = "c";
a.add_arc(b); //a should point to b
a.add_arc(c); //a should point to c
nodes.push_back(a);
nodes.push_back(b);
nodes.push_back(c);
cout << nodes[0].next.size() << endl; // prints "2", works fine
cout << nodes[0].next[0]->some_string << endl; //empty
}
I thought it would be as easy as just overloading push_back:
void push_back(vertex * pointer)
{
next.push_back(pointer);
}
But I think I really need a copy constructor, or some other method to make this work. How would I go about doing this for a vector of pointers?
Edit: I guess I didn't explain it well. Look at the answers in this question:
Segmentation fault when accessing a pointer's member function in a vector
Making 'a' a reference did not work for me
It works...
Your code generates as expected the correct output (see online demo):
2
b
...However this design is not future proof
However this result is related somehow to luck, because in your code snippet:
the nodes in the nodes vector are copies of the original object including all their pointers
the local objects a, b, c to which these pointers point still exist
However in more complex code, you'd quickly end up with dangling pointers.
Imagine:
Bad example 1: you create a graph, keeping all the nodes directly in a vector of nodes. You then add the first arcs between the nodes. As soon as you'll add a new node to the vector, reallocation might occur and you'd risk to see all your next pointers invalidated.
Bad example 2: you initialise a graph like you did, but in a function called by main. In this case, as soon as you return from this function, all the local nodes get destroyed and the vector's node will point to objects that do no longer exist. UB guaranteed !
How to improve ?
Your design fails to recognize that the nodes all belong to the same graph.
There is a quick and dirty way out: always create the node from the free store, and store them in a vector<node*>.
vector<node*> nodes;
node *a = new node("a"); // Imagine a node constructor
node *b = new node("b");
a->add_arc(b); //change signature, to accept a pointer
nodes.push_back(a);
nodes.push_back(b);
There's a better approach: improve further the previous approach, but use shared_ptr<node*> to make sure that nodes that are no longer referenced (neither by a vector of nodes, nor by an arc) are destroyed automatically.
There's an even better approach: encapsulate the nodes in a class representing a graph. In this case, you could consider using a vector<nodes> and replace the pointers in next, by indexes of the target nodes in the vector. No pointer, but perfect copy of graphs will be much easier. And no more memory management hassle.
class node // just to give the general idea
{
public:
vector<int> next; // not usable without the graph
void add_arc(int a)
string id;
};
class graph {
vector<node> nodes;
public:
void add_node (node a);
void add_arc (string from, string to);
node& operator[] (size_t i);
...
};
i wrote the following code to delete the nodes at the beginning and at the end of a doubly linked list....but the execution of these functions stopped in between and the program was aborted......
struct nodeb
{
int value;
nodeb *next;
nodeb *pre; //pre of first node and next of last node point to null...
nodeb(int a,nodeb *ptr1=0, nodeb *ptr2=0):value(a), next(ptr1), pre(ptr2)
{}
};
class doublelist
{
private:
nodeb *head1,*head2;
public:
doublelist():head1(0),head2(0)
{cout<<"double list created"<<endl;}
void deletebeg()//delete beginning node
{
if(head1->next==0)
{
nodeb *ptr=head1;
head1=head2=0;
delete ptr;
}
else
{
nodeb *ptr=head1->next;
nodeb *ptr1=head1;
ptr->pre=0;
head1=ptr;
delete ptr1;
}
}
void deleteend()//delete end node
{
nodeb *ptr=head1;
nodeb *ptr1;
while(ptr->next!=0)
{
ptr1=ptr;
ptr=ptr->next;
}
delete ptr;
ptr1->next=0;
}
}; //class ends here
int main()
{
doublelist list1;
nodeb node(8);
nodeb node1(7);
nodeb node2(9);
nodeb node3(4);
list1.insertbeg(node);
list1.insertbeg(node1);
list1.insertafter(node3,1);
list1.insertend(node2); //insertbeg,insertafter and insertend are three functions i defined to attach nodes at the beginning,at a particular location and at the end of the list
list1.deletebeg();
}
can anyone please tell me the problem??this is the link to the three functions for insertions
Now I can see all the code the problem is very simple. Your deletebeg function is deleting the beginning node with delete, but you didn't allocate the node with new. You should only delete memory if you created it using new.
Normally when people write linked list classes they allocate the nodes inside the list methods using new. Then they can safely delete the nodes inside the methods. You are doing the deletes but you are not using new. So you need to rewrite your main function like this
int main()
{
doublelist list1;
list1.insertbeg(8); // add 8 to beginning of list
list1.insertbeg(7); // add 7 to beginning of list
list1.insertafter(4,1); // add 4 after first item of list
list1.insertend(9); // add 9 to end of list
list1.deletebeg();
}
Then you need to rewrite your methods like this
void insertbeg(int value)//insert beginning
{
nodeb* a = new nodeb(value); // allocate node inside of method using new
if(head1==0)
{
head1=a;
head2=a;
a->next=0;
a->pre=0;
}
else
{
nodeb *ptr=head1;
ptr->pre=a;
a->pre=0;
a->next=ptr;
head1=a;
}
}
I've only shown insertbeg, you need to change all your insert methods in the same way.
I'm not promising that's the only problem, but make this change and you'll be on the right way. If you have more problems then post again, but remember post complete code. It's the only way you'll get help with problems like this.
I'm a little baffled by this code excerpt, but I'll assume this is the entire excerpt for this...
The functions deletebeg and deleteend aren't declared anywhere in the class definition, only after it. Normally, it would look something like:
class List{
void aFunction(List * argument);
};
void List::aFunction(List * argument){
do something
};
But all that aside, do not make your own linked list, it is much faster and will make your life easier using std::list<int> (replacing int with whatever data type you are making a list for).
There are lots of reasons for this, but the main one is that you only don't have to write it, but you don't have to debug it either. The linked list implementation you created, for instance, uses a recursive function to delete itself (when a function calls itself, it's recursive). If the linked list is very large, this can cause a stack overflow, caused by calling too many functions within functions. It's things like this that are a nightmare to track down and find, and distract you from the real reason you are programming. That is assuming that reason isn't making a linked list. :P
While it isn't usual to see functions declared outside a class in C++, it isn't impossible. But that would mean that head1 is a global variable somewhere that isn't shown.
You left out the part of that is actually calling deletebeg and deleteend so it is hard to tell exactly what is happening. Perhaps you are making use of a pointer after it has been deleted.
Also, while NULL is usually zero, there is no guarantee that is the case for your compiler. You should be using NULL instead of zero.
My guess is that you called deleteend with a node that for whatever reason had head1==0, then ptr1 was never initialized, and the program crashed on the last line of deleteend when you tried to dereference the uninitialized pointer.
Further to the comments on my previous answer
This code is wrong
void insertbeg(int value)//insert beginning
{
nodeb a(value); // create node on the stack
if(head1==0)
{
head1=&a;
head2=&a;
a.next=0;
a.pre=0;
}
else
{
nodeb *ptr=head1;
ptr->pre=&a;
a.pre=0;
a.next=ptr;
head1=&a;
}
}
The code above would have the problem you described, when you said 'head1 and head2 will point nowhere'. But this code is completely different
void insertbeg(int value)//insert beginning
{
nodeb* a = new nodeb(value); // allocate node inside of method using new
if(head1==0)
{
head1=a;
head2=a;
a->next=0;
a->pre=0;
}
else
{
nodeb *ptr=head1;
ptr->pre=a;
a->pre=0;
a->next=ptr;
head1=a;
}
}
It's different because it uses new to create the objects. When you use new the objects don't get destroyed when you exit the function. That's what new means. But when you do use new you also have to use delete when you have finished with the nodes.
While trying to learn c++, I tried to implement class representing very basic trie. I came up with the following:
class Trie {
public:
char data;
vector<Trie* > children;
Trie(char data);
Trie* addChild(Trie* ch); // adds child node
(skipped others members/methods)
};
Method addChild checks if child ch with the same data is present in vector children, if not then it inserts it there, if yes - returns pointer to already existing child.
Now, considering this code snippet:
Trie t('c');
Trie* firstchild = new Trie('b');
Trie* secondchild = new Trie('a');
firstchild->addChild(secondchild);
t.addChild(firstchild);
if I only have pointer to secondchild, is it possible to somehow return pointers to firstchild or maybe even t?
I would like to know if it possible to do so, because the logic of my working code needs to traverse the trie "up" (from lower nodes to upper ones), to the parent of current object. Currently I am just using recursive function to travel down - but I am wondering if there exists any other way?
I am sorry if above is unclear or if I messed up somewhere, I am rather inexperienced and writing from my memory, without the working code.
You need to add something like
Trie* parent;
or
Trie* previoussibling;
Trie* nextsibling;
to the class to get directly from firstchild to secondchild or vice-versa, or to go up from one of the children to t.
Note that if you need this kind of relationship then you will require more maintenance when adding and removing nodes to keep all the links correct.
The Trie object does not keep track of parent object.
Its basically similar to single linked list and you can not traverse back unless you "know" the parent.
class Trie {
public:
char data;
vector<Trie* > children;
Trie* parent;
Trie(char data):parent(NULL){}
Trie* addChild(Trie* ch)
{ //set the parent
ch->parent = this;
}
(skipped others members/methods)
};
Then traverse would look something like:
traverse(Trie* pPtr)
{
Trie* currentPtr = pPtr;
while(currentPtr)
{
currentPtr = currentPtr->parent;
}
}
I only have pointer to secondchild,
is it possible to somehow return
pointers to firstchild or maybe even
t?
No. You have to establish that relationship your self by passing the firstChild as a parent of the second child.