in this code, I think it must do deep copy because I'm passing pointers, but it doesn't.
I think it must print 3, but print 0. what should I do to solve this? i want to have a deep copy instead of a shallow copy.
struct node{
int number = 0;
struct node* right_child = NULL;
struct node* left_child = NULL;
};
void test(struct node* node1 , struct node* node2){
node1 = node2;
}
int main(){
struct node* a1 = new struct node;
struct node* a2 = new struct node;
a2->number = 3;
test(a1 , a2);
cout << a1->number;
}
The simple C-ish way: We ad a function that recursively clones the nodes
#include <iostream>
struct node{
int number = 0;
node* right_child = nullptr; // nullptr safer than NULL
node* left_child = nullptr;
};
node * clone(const node * src){
if (src) { // there is a node. Copy it.
return new node{src->number,
clone(src->right_child), // clone right
clone(src->left_child)}; // clone left
}
else { // no node. Nothing to do and end the branch
return nullptr;
}
}
void test(node*& node1, // reference to pointer
node* node2){
delete node1; // Free storage currently used by node1
// But what of the nodes that could be in its tree?
// Think on this. Ask another question if necessary.
// this is where the simple way starts to fall down
node1 = clone(node2);
}
int main(){
struct node* a1 = new node; // wasted memory. We're about to replace it.
// need a more complicated tree to prove deep copy works
struct node* a2 = new node{3,
new node{4, nullptr, nullptr}, // a right node
nullptr}; // no left node
// a2->number = 3; done above now
test(a1 , a2);
std::cout << a1->number << ' '
<< a1->right_child->number;
delete a1; // clean up
delete a2;
}
More complicated canonical C++ way using The Rule Of Three and The Copy and Swap Idiom
#include <iostream>
#include <algorithm> // for std::swap
struct node{
int number = 0;
node* right_child = nullptr; // nullptr safer than NULL
node* left_child = nullptr;
static node * clone(node * src)
{
if (src)
{
return new node(*src);
}
return nullptr;
}
// generic constructor
node(int number = 0,
node* right_child = nullptr,
node* left_child = nullptr):
number(number),
right_child(right_child),
left_child(left_child)
{
}
//copy constructor
node (const node & src):
number(src.number),
right_child(clone(src.right_child)),
left_child(clone(src.left_child))
{
}
// assignment operator via copy and swap.
node & operator=(node src)
{
std::swap(number, src.number);
std::swap(right_child, src.right_child);
std::swap(left_child, src.left_child);
return *this;
}
// destructor
~node()
{
delete right_child;
delete left_child;
}
};
void test(node* node1,
node* node2){
*node1 = *node2; // now, thanks to all of the infrastructure above, we can
// assign nodes with the dumb old = operator. All we have to do
// is dereference the pointers.
}
int main(){
struct node* a1 = new node; // wasted memory. We're about to replace it.
// need a more complicated tree to prove deep copy works
struct node* a2 = new node{3,
new node{4, nullptr, nullptr}, // a right node
nullptr}; // no left node
// a2->number = 3; done above now
test(a1 , a2);
std::cout << a1->number << ' '
<< a1->right_child->number;
delete a1; // clean up
delete a2;
}
All of the nodes are now self-managing.
But, my opinion, the nodes should be kept as dumb as they are in the simple example. They shouldn't need to know about the tree at all. Knowledge of the tree should be in a Tree class that uses the nodes as simple containers. The Tree class should do all of the management of the nodes--creating, copying, cloning, deleting--because only it knows everything necessary to represent the tree. The users of the tree shouldn't even know nodes exist. They put data into the tree, take data out of the tree, and observe the tree without caring how the tree works and being able to so something stupid like
delete a_node;
and blow the crap out of data the tree isn't done with yet.
The Tree class preferably works iteratively rather than recursively so that the trees can be arbitrarily sized. Unless you're really careful recursing through a large tree to clone it, delete it, display it, or pretty much anything else you do with a tree runs the risk of exhausting automatic storage and causing what's typically called a Stack Overflow.
just use
void test(struct node *node1, struct node *node2) { *node1 = *node2; }
instead of
void test(struct node *node1, struct node *node2) { node1 = node2; }
and it will print 3.
This is because...
when you do node1 = node2; int the test1, you assign the pointer itself, not the structure pointed to by the pointer.When the function ends, the parameters node1 and node2 will be destroyed, so you have done nothing...
Related
Today I was taught Linked list in class and I wanted to implement it on my own.
Here's the part of the code that I wrote. Note that traverseLL traverses the Linked list and insertAtEnd inserts a new node at the end of the linked list.
I believe I can implement Linked list logic / methods / functions on my own. But my question is, inside insertAtEnd function when I create a newNode with the parameters - my data to be inserted, and nullptr (because inserting at the end), It inserts garbage values (or memory addresses maybe) in my node, ignoring the data passed to the constructor.
using namespace std;
#define NL '\n'
class Node {
public:
int data;
Node* next;
Node (int data, Node* nextPtr=nullptr) {
data = data;
next = nextPtr;
}
};
void insertAtEnd(Node* &head, int data) {
Node* newNode = new Node(data, nullptr); // <---- Issue in this line
// When I do as above, my linkedlist nodes always store garbage values and not the data being passed.
// However, when I un-comment the below line, I get the correct output.
// newNode->data = data;
if (head == nullptr)
head = newNode;
else {
Node* temp = head;
while (temp->next != nullptr)
temp = temp->next;
temp->next = newNode;
}
}
void traverseLL(Node* head) {
if (head == nullptr)
return;
while (head->next) {
cout << head->data << " -> ";
head = head->next;
}
cout << head->data << NL;
}
int main() {
Node* head = nullptr;
insertAtEnd(head, 10);
insertAtEnd(head, 20);
insertAtEnd(head, 30);
traverseLL(head);
return 0;
}
For example, the output for the above code when keeping newNode->data = data line commented, is :
16259544 -> 16258392 -> 16258392
But when I un-comment that line, my output becomes, which is intended:
10 -> 20 -> 30
Why is this happening? Even though I've defined my constructor, why is it not working?
I think the cause for this is the statement data = data in the constructor.
Reason for this:
Before executing the first statement of constructor, the member variables of the class are allocated memory and contain junk/default values, and when the statement data = data is seen the compiler changes the parameter but not the member variable.
As a result, you are seeing junk/garbage values.
To resolve this we can either explicitly specify the member using this or use member initialization syntax.
You can use any of the following workarounds.
Workarounds:
You can change your class constructor code like any of the below formats:
1.
class Node {
public:
int data;
Node* next;
Node (int data, Node* nextPtr=nullptr) {
this->data = data; // we are explicitly specifying which data to use
next = nextPtr;
}
};
class Node {
public:
int data;
Node* next;
Node (int d, Node* nextPtr=nullptr) {
data = d; // as the member variable and local variable are of different names, no conflict
next = nextPtr;
}
};
class Node {
public:
int data;
Node* next;
// use the member initialization syntax
// Here we are initializing the data while allocating memory itself,
// so answer is perfectly right!
Node (int d, Node* nextPtr=nullptr) : data(data), next(nextPtr) {}
};
More on the member initialization and constructor:
https://en.cppreference.com/w/cpp/language/constructor
How do C++ class members get initialized if I don't do it explicitly?
Hope this helps,
Thanks.
This question already has answers here:
Binary Search Tree Destructor
(6 answers)
Closed 2 years ago.
Please help me. I am stuck at this.
What am I trying to do: Binary search tree.
I am a C# developer and I learn C++ for about 2 weeks, therefore don't be so harsh with me and that's why pointers are still difficult for me.
I have a struct Node
struct Node
{
int Value;
Node* _LeftNode;
Node* _RightNode;
Node(int value)
: Value(value), _LeftNode(NULL), _RightNode(NULL)
{
}
};
and a Delete() function in BinarySearchTree.cpp
void BinarySearchТрее::Delete(Node* node)
{
if (node)
{
Delete(node->_LeftNode);
Delete(node->_RightNode);
delete(node);
node = NULL;
}
}
I want to delete the node and all of its child nodes.
When I first step in the recursion... For example:
I have two child nodes with values 10 and 19.
With recursion, I delete the nodes and set the pointers to NULL.
And here is the problem:
When I came out from the recursion the nodes are not NULL, but something strange.
And this is my problem. Why when I am in the recursion and I NULL the pointer everything is fine, but when I come out the pointer is something else.
As I talked in the comments, I think the thing is that how we can reset the pointer of the parent's(left or right child) of the initially passed node. (recursively deleting a node and its all children looks good.)
And I don't think it is possible in your current design. As Node does not contain a pointer to its parent, so there is no way to know who's the parent. node = NULL sets just the argument(local variable)'s value so it is pointless.
The C++ way would be to use std::unique_ptr.
struct Node
{
int Value;
std::unique_ptr<Node> LeftNode;
std::unique_ptr<Node> RightNode;
Node(int value)
: Value(value)
{
}
};
Then to destroy a node and all of its children, you'd call reset on the appropriate std::unique_ptr<Node>
I think what you actually want ist this:
struct Node
{
int Value;
Node* _LeftNode;
Node* _RightNode;
Node(int value)
: Value(value), _LeftNode(NULL), _RightNode(NULL)
{
}
~Node() {
delete _LeftNode;
delete _RightNode;
}
};
This way you are using the destructor to clean up recursivly.
delete nullptr is ok btw.
EDIT:
the unique_ptr<> usage in one of the other answers is probably the smarter way to do this.
Given:
struct Node
{
int data = 0;
struct Node * left = nullptr, * right = nullptr;
Node(int data) { this->data = data; }
};
This recursive function deletes a node & its childs (+ one comment):
void DeleteTree(struct Node* node) // A copy of the caller pointer
{
if (node)
{
DeleteTree(node->left); // Recur on left subtree
DeleteTree(node->right); // Recur on right subtree
delete node;
// node = nullptr; <-- This line is useless
}
}
To your wondering "but when I come out the pointer is something else":
There is no point in node = nullptr line, since when you call DeleteTree(my_node) function, node is a copy of my_mode, so when you set node = nullptr it has no effect on my_node that on exit from DeleteTree(my_node) points to a deleted, invalid object.
--
Possible solution:
#define DELETE_TREE(node) DeleteTree(node); node = nullptr; // Macro
int main()
{
struct Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
DELETE_TREE(root->left); // root->left became nullptr
DELETE_TREE(root); // root became nullptr
return 0;
}
After DeleteTree function, the caller pointer points to an invalid object since its object already released. A possible solution is to define a DELETE_TREE Macro to "auto-nullify" the caller pointer after DeleteTree function.
--
Implementation with Modern C++ Smart Pointers:
#include <memory>
struct Node
{
int data = 0;
std::unique_ptr<Node> left, right;
Node(int data) { this->data = data; }
};
int main()
{
std::unique_ptr<Node> root;
root = std::make_unique<Node>(1);
root->left = std::make_unique<Node>(2);
root->right = std::make_unique<Node>(3);
root->left->left = std::make_unique<Node>(4);
root->left->right = std::make_unique<Node>(5);
root.reset();
return 0;
}
I have a problem with working with c++ pointers. I'm trying to code a splay tree by using a Node struct and Tree struct. However, upon testing, I have encountered a problem. The portion of my code that's not working is below:
struct Node {
Node* l, *r, *p;
int v;
Node() {}
Node(int _v, Node* _p) : v(_v), p(_p) {}
};
struct Tree {
Node* root;
Tree() : root(0) {}
//...
void insert(int k) {
if (!root) {
root = new Node(k, 0);
return;
}
Node* cur = new Node();
cur->v = root->v;
while (1) {
int x = cur->v;
cout << x << endl;
return;
if (k <= x) {
//cout << x << endl;
//return;
if (!cur->l) {
cur->l = new Node(k, cur);
//splay(cur->l);
return;
} else cur = cur->l;
} else {
if (!cur->r) {
cur->r = new Node(k, cur);
//splay(cur->r);
return;
} else cur = cur->r;
}
}
}
//...
};
int main() {
Tree t = Tree();
t.insert(1);
t.insert(5);
return 0;
}
First, I inserted a node with value 1 in the tree; since there was no root, the tree assigned its root as a new node with value 1. Then, when I inserted 5 into the tree, something weird happened. If you leave the code like it is (keeping the first cout), then it will print out 1 for x. However, if you comment out the first cout and return and uncomment the second cout and return, you'll find that it prints out a random garbage number for x, even though no modifications were made. Can somebody tell me what's wrong?
C++ does not initialize class members automatically.
struct Node {
Node* l, *r, *p;
int v;
Node() {}
Node(int _v, Node* _p) : v(_v), p(_p) {}
};
When you create a new node in your code C++ allocates a piece of memory for the Node but it will not clear it. So the values of l, r & p will be whatever was there.
In your algorithm the tests: if (!cur->r) & (!cur->l) currently fail because there is uninitialized garbage in the nodes and not NULL.
As a result when you try to insert the second node the algorithm thinks that there is a valid node to the right of root. And tries to read the memory there and the value there which is the junk x you see. Depending on the value of the junk it may also crash for some people running the code :)
Also I'm 99.9% certain that Node* cur should be a pointer to a Node in the tree and not a new node so:
Node* cur = new Node(); cur->v = root->v; is wrong and should be Node* cur = root;
Proper Initialization -
In c++11 you can do:
struct Node {
Node* l = nullptr;
Node *r = nullptr;
Node *p = nullptr;
int v = 0;
Node() {}
Node(int _v, Node* _p) : v(_v), p(_p) {}
};
Otherwise
struct Node {
Node* l;
Node *r;
Node *p;
int v;
Node() : l(NULL), r(NULL), p(NULL), v(0){}
Node(int _v, Node* _p) : l(NULL), r(NULL), p(_p), v(_v) {}
};
You should initialize members of a class in the same order they were defined.
Now there are a lot of other things that are problematic in the code:
Tree seems to allocate lots of nodes but does not release any memory. (easiest to just use unique_ptr for l and r and root Node)
Is tree the owner of subnodes? Or should it be Node owning and allocating left and right? (goes away if you use std::unique_ptr for left and right)
You are not initializing the members in the order they are defined. This can cause all kind of errors. (since the compiler reorders initialization without telling you)
Node and Tree handle raw pointers but do not define a proper operator=, copy ctor (or delete them) (goes away if you use unique_ptr)
Tree is missing a dtor to clean allocated memory (goes away if you use unique_ptr)
I've just implemented the Linked List. It works perfectly fine but even tough I've seen notation I am unable to create working destructor on Node, that's why it's unimplemented here in code.
I need to implement working destructor on node
Destructor of List but this one is simple I will just use the destructor from Node class(but I need this one).
Make the List friendly to Node so I will not have to use getNext(), but I think I can
handle it myself(not sure how, but I'll find out).
Please look at the code it is perfectly fine, just will work if you copy it.
#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class Node {
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
Node(const Node& obiekt) {
this->wrt = obiekt.wrt;
this->next = obiekt.next;
}
~Node() {}
void show() {
cout << this->wrt << endl;
}
int getWrt(){
return this->wrt;
}
Node* getNext(){
return this->next;
}
void setNext(Node* node){
this->next = node;
}
private:
Node* next;
int wrt;
};
class List{
public:
List(int wrt){
this->root = new Node(NULL, wrt);
}
List(const List& obiekt){
memcpy(&this->root,&obiekt.root,sizeof(int));
Node* el = obiekt.root->getNext();
Node* curr = this->root;
Node* next;
while(el != NULL){
memcpy(&next,&el,sizeof(int));
curr->setNext(next);
curr = next;
next = curr->getNext();
el = el->getNext();
/* curr->show();
next->show();
el->show(); */
}
}
void add(int wrt){
Node* node = new Node(NULL, wrt);
Node* el = this->root;
while(el->getNext() != NULL){
//el->show();
el = el->getNext();
}
el->setNext(node);
}
void remove(int index){
Node* el = this->root;
if(index == 0){
//deleting old one
this->root = this->root->getNext();
}
else{
int i = 0;
while(el != NULL && i < index - 1){
// el->show();
el = el->getNext();
i++;
}
if(el!=NULL){
Node* toRem = el->getNext();
Node* newNext = toRem->getNext();
el->setNext(newNext);
//deleteing old one
}
}
}
void show(){
Node* el = this->root;
while(el != NULL){
el->show();
el = el->getNext();
}
}
~List(){}
private:
Node* root;
};
int main(){
List* l = new List(1); //first list
l->add(2);
l->add(3);
l->show();
cout << endl;
List* lala = new List(*l); //lala is second list created by copy cosntructor
lala->show();
cout << endl;
lala->add(4);
lala->remove(0);
lala->show();
return 0;
}
I suggest you to start with implementing destructor of List. Since you dynamically allocated memory by using new, you should free it by using delete. (If you used new[], it would be delete[]):
~List()
{
Node* currentNode = this->root; // initialize current node to root
while (currentNode)
{
Node* nextNode = currentNode->getNext(); // get next node
delete currentNode; // delete current
currentNode = nextNode; // set current to "old" next
}
}
Once you have proper destructor, you should try whether your copy constructor is correct:
List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy
you will find out that your copy constructor is wrong and also causes your application to crash. Why? Because purpose of copy constructor is to create a new object as a copy of an existing object. Your copy constructor just copies pointers assuming sizeof(Node*) equal to sizeof(int). It should look like this:
List(const List& list)
{
// if empty list is being copied:
if (!list.root)
{
this->root = NULL;
return;
}
// create new root:
this->root = new Node(NULL, list.root->getWrt());
Node* list_currentNode = list.root;
Node* this_currentNode = this->root;
while (list_currentNode->getNext())
{
// create new successor:
Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
this_currentNode->setNext(newNode);
this_currentNode = this_currentNode->getNext();
list_currentNode = list_currentNode->getNext();
}
}
Also your function remove is wrong since it "removes" reference to some Node but never frees memory where this Node resides. delete should be called in order to free this memory.
"I need to implement working destructor on node" - No, you don't. Node itself doesn't allocate any memory, thus it shouldn't free any memory. Node shouldn't be responsible for destruction of Node* next nor cleaning memory where it's stored. Don't implement destructor nor copy constructor of Node. You also want to read this: What is The Rule of Three?
"Make the List friendly to Node so I will not have to use getNext()" - You want to say within Node class, that class List is its friend:
class Node
{
friend class List; // <-- that's it
Note that from these 5 headers that you include your code requires only one: <iostream>.
Also note that writing using namespace std; at the beginning of the file is considered bad practice since it may cause names of some of your types become ambiguous. Use it wisely within small scopes or use std:: prefix instead.
The linked list destructor will be called either when delete is used with a previously allocated pointer to a linked list or when a linked list variable goes out of scope (e.g., a local variable is destroyed when returning from a function).
The destructor for the linked list should be responsible to free the memory you previously reserved for the nodes (i.e., using add operation). So, basically, you need to traverse the list of nodes and apply the delete operation on each one of them. There is a little trick: when you are about to delete a node you must be careful not to lose the pointer to the next element (when a node is deleted you cannot be sure that next member will still be valid).
If you want to create a destructor for your Node, it should be quite simple actually.
Here it is:
class Node {
private:
int wrt;
Node* next;
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
// Your desired destructor using recursion
~Node() {
if ( next != NULL )
delete next;
}
};
It's that simple :)
Basically, right before the Node is deleted, if next is not empty, we delete next, which will again call the destructor of next, and if next->next is not empty, again the destructor gets called over and over.
Then in the end all Nodes get deleted.
The recursion takes care of the whole thing :)
How do you allocate memory for an link list when passing its reference instead of its pointer?
For example:
struct node {
string info;
node *next;
};
void add(node &aNode){
//if I use
node *newNode;
newNode = new node;
aNode.next = newNode; //aNode.next = newNode; doesn't work either
//allocating on heap seems to give segmentation error.
}
int main() {
node *aNode;
aNode = new node;
add (aNode);
}
Compiler error: error: invalid initialization of reference of type ‘node&’ from expr
alternatively if I use
int main() {
node aNode;
add (aNode);
add (aNode);
aNode.next->next->info = "abc";
string a = aNode.next->next->info;
}
This give segmentation fault.
So is it possible to allocate for an linked list just with its reference? (this is C++)
It should be
node * newNode = new node;
aNode.next = newNode
You have to take care of deletion manually, e.g. check if aNode.next isn't already occupied (and delete if it is).
Further, the add function signature should read:
void add(node & aNode) { ... }
By the way, the STL comes with a nice <forward_list> ;-)
It's hard to tell what you're actually asking, but going by the question title perhaps you have in mind a node structure like this:
struct Node {
Node & next;
/* payload data */
Node(Node & n) : next(n) /* ... */ { }
};
Such a node would store its successor "by reference"; but you would have to initialize it with an existing node! (There is no such thing as a "null" reference.) By the Poultry-Oval Impasse, you cannot do this.
Alright, while you continue to refuse to post your full code, here is my almost literal copy/paste of your code which works fine with me:
Update: I'm adding a feature to add a node at the end, which you might want.
#include <string>
struct node {
std::string info;
node *next;
node(std::string i = "") : info(i), next(NULL) { }
};
void add(node &aNode)
{
node *newNode;
newNode = new node;
aNode.next = newNode;
}
void add_at_end(node &aNode, std::string value = "")
{
node *newNode, *n = &aNode;
while (n->next) n = n->next; // move to the end
newNode = new node(value);
n->next = newNode;
}
int main()
{
node aNode, bNode;
add(aNode);
add_at_end(bNode, "Hello");
add_at_end(bNode, "World");
add_at_end(bNode, "!");
}
Compile with g++ -o prog prog.cpp -W -Wall -pedantic.
Finally, here's the STL way of achieving the same thing:
#include <forward_list>
#include <string>
int main() {
std::forward_list<std::string> bList;
bList.push_front("Hello");
bList.push_front("World");
bList.push_front("!");
}
In your second variant of main(), you are calling add(aNode) twice. But you're providing it the same parameter each time. So although you're creating two new node objects, one of them is lost forever (a memory leak). And aNode.next ends up pointing to the other one. aNode.next->next is not a valid pointer, hence the seg-fault when you try to access something through it.
Depending on what you want to achieve, you could try this:
node aNode;
add(aNode); // Basically does: aNode.next = new node;
add(*aNode.next); // Basically does: aNode.next->next = new node;
There are better ways of doing linked-lists, but this would at least avoid the seg-fault.
Try
int main() {
node *aNode;
aNode = new node;
add (*aNode);
}
You have to pass reference to object, not a pointer.
I checked your code and I didn't get segmentation fault when allocating on stack: http://ideone.com/gTRIG.
My proposition:
#include <string>
using namespace std;
struct node {
string info;
node *next;
node(string str): info(str), next(NULL) {}
~node() { if(next != NULL) delete next; }
node *add(string info){
node *newNode = new node(info);
return aNode.next = newNode;
}
};
int main(){
node rootNode("My rootnode");
node *nxt = rootNode.add("Next node");
nxt->add("Last node");
// No need to call delete, because destructor will clear heap
}