I'm creating an implementation of a Trie with a TrieNode struct which is an individual node and a TrieSet class which is the complete tree. Here is the signature of my TrieNode:
struct TrieNode {
TrieNode(bool in, TrieNode *p);
~TrieNode();
void deleteChildren(TrieNode *node);
bool isLeafNode();
bool inSet;
TrieNode *parent;
TrieNode *children[30];
};
I'm trying to define the destructor which first recursively deletes all the children and then finally deletes the node, but I'm getting a segmentation fault. Here is the code for my constructor, destructor and its helper function:
TrieNode::TrieNode(bool in, TrieNode *p)
{
inSet = in;
parent = p;
}
TrieNode::~TrieNode()
{
for(int i = 0; i < 30; i++)
{
if(children[i] != nullptr)
{
delete children[i];
}
}
}
Any help would be appreciated, thanks!
The children array is uninitialized, so the data will be random garbage and trying to delete them Undefined Behavior, and likely a crash.
Calling delete node in deleteChildren is wrong, as it results in a recursive destructor call (just like calling delete this from within the destructor).
There may be other issues. I haven't looked extensively.
Related
I have made a superclass named "tree". I have constructed the tree in this class. Now, I want to pass the root of the constructed tree to another class which is a subclass of tree. But when I try to pass it, the subclass calls the supercalss constructor and sets it to NULL;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
This is the definition of my tree class. It just creates a tree with one node having value 5. Now I want to pass the new root created to a subclass of tree.
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
I create an object for tree first and then do createtree. Now, when I create an object for treeiterator, it's member p gets sets to NULL since supercalss constructor is also called. How can I just access the tree created in the superclass in subclass?
Full code:
#include <bits/stdc++.h>
using namespace std;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
void treeiterator::push(struct node *t)
{
while(t) {
s.push(t);
t = t->left;
}
}
bool treeiterator::hasnext()
{
return s.empty()?1:0;
}
int treeiterator::next()
{
struct node *t = s.top();
int val = t->val;
s.pop();
if(t->right) {
push(t->right);
}
return val;
}
int main()
{
tree t;
t.createtree();
t.preorder();
treeiterator it;
while(it.hasnext()) {
cout<<it.next()<<' ';
}
}
Because of inheritance every treeiterator is also a tree. This means
treeiterator treeIt;
treeIt.createtree();
will do what OP wants. There is no need to make a separate tree and moving the root around.
However this is a bit odd in the world of C++ because OP is under-using the constructor. For example, node could be:
struct node
{
node *left;
node *right;
int val;
node(int inval):
val(inval),
left(nullptr),
right(nullptr)
// the above is a Member Initializer List. It makes sure all of your
// members are initialized before the body of the constructor runs.
{
}
};
That bit after the : in the constructor is the Member Initializer List.
Now when you allocate a node it's initialized and ready to be linked. For tree
class tree
{
public:
struct node *root; // almost certainly should not be public.
// also should be a std::unique_ptr<node>
tree(int inval)
{
root = new node(5); // note new in place of malloc. new allocates
// storage and calls constructors. malloc should
// only be used in C++ in rare edge-cases.
}
/* obsolete
void createtree()
{
root = create(5);
}
*/
...
};
tree is assigned a root on allocation. treeiterator is a wee bit trickier because it must call tree's constructor to set up root.
class treeiterator:public tree
{
struct node *p; // Don't see the point off this
stack<struct node *> s; // or this, but that's another question
public:
treeiterator(int inval):
tree(inval) // call's tree's constructor
{
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
Allocating a treeiterator now guarantees that it is all ready to go with no further work.
treeiterator treeIt(5); // all done.
All of the above is covered within the first few chapters of any good C++ programming text. I recommend getting one and reading it, because right now it looks like you are trying to write bad C.
Off topic 1:
You are going to quickly find that this code is in violation of the Rule Of Three. What is The Rule of Three? If you don't know, read the link. It will save you much time and hair-pulling
Off Topic 2:
#include <bits/stdc++.h>
using namespace std;
Is a ticking time bomb. The first line includes the entire standard library, but only in GCC. Your code is now doing far, far more work than it need to to compile, is no longer standard C++, and is not portable to other compilers and may well break with the next revision of GCC. Don't use anything in bits. It internal compiler-specific stuff with no guarantees what-so-ever.
More here: Why should I not #include <bits/stdc++.h>?
The second line takes everything in the std namespace and places it in the global namespace. This leads to fun games like is reverse or std::reverse being called? Often this leads to insane and arcane compiler messages because the poor compiler is confused as hell, but sometimes it's not confused and picks the best choice among the many and silently breaks something else. Great fun debugging.
More here: Why is "using namespace std" considered bad practice?
Together you have the entire standard library pulled into your file AND stripped of it's proper namespace. This results in a vast minefield of potential hidden pain that is not worth any perceived time savings. One of the resulting bugs could cost more clean up than years of typing a few extra lines per file and characters.
No one want to clean up code with this stupid a mistake, so doing this in a professional setting can be costly.
First, you should not have root has public. This is a gross OO error. If you want it to be available to subclasses you should make it protected.
I have a one-dimensional template list that contains nodes, each node has a link to next node.
It works rather well on it's own, but not when it contains another linked list.
LinkedList and Node looks something like that:
template <class T>
class LinkedList
{
private:
Node<T>* pPreHead;
public:
LinkedList(void);
~LinkedList(void);
Node<T>* getHead(void);
int size();
void addElementToEnd(T& value);
void deleteNextNode(Node<T>* pNodeBefore);
}
template <class T>
class Node
{
private:
T value;
Node* next;
public:
Node();
Node* getNext();
Node* getValue();
void setNext(Node* nextElem);
void setValue(T elem);
};
Now for the task I need to use LinkedList>, which is filled via a loop.
It looks something like this:
ifstream fl;
fl.open("test1.in", std::ifstream::in);
while (fl.good())
{
string currentLine;
getline(fl, currentLine);
LinkedList<string> newDNA;
//newDNA being filled here so I skipped code
DNAStorage.addElementToEnd(newDNA);
//Place 1
}
//Place 2
Now if I insert some test output code in "Place 1" everything is fine, but when the loop enters new iteration newDNA variable gets freed and so is the pointer inside DNAStorage (which is LinkedList<LinkedList<string>> in question), and when I try to print anything in "Place 2" I get segmentation fault.
Unfortunately I can't use any other data structures since this is the kind of task I need to do.
My question is - how can this be fixed, so that it actually is not freed prematurely?
Edit:
Here's my code for AddElementToEnd(T& value):
template <class T>
void LinkedList<T>::addElementToEnd(T &value)
{
Node<T> *newtail = new Node<T>;
newtail.setNext(NULL);
newtail.setValue(value);
if(pPreHead == NULL)
{
pPreHead = newtail;
return;
}
Node<T> *tail = pPreHead;
while(tail.getNext() != NULL)
{
tail = tail.getNext();
}
tail.setNext(newtail);
}
The problem is that you are storing references to objects that are going out of scope, causing undefined behavior when you try and access them. Your LinkedList<string> newDNA gets created and destroyed with each iteration of the while loop, yet you pass a reference to be stored in DNAStorage list.
One solution would be to store a copy of each object (not reference) in the list when addElementToEnd() gets called.
I always seem to get in trouble when I'm deleting all nodes from a tree. I am trying to release all the memory I allocated when creating a trie tree.
I am suppose to create a function remove_all
Is it enough to delete just the "root"
something like this:
void PrefixStringSet::remove_all(NodePtr node)
{
delete root;
}
Or do I have to delete each node with something like this:
void PrefixStringSet::remove_all(NodePtr node)
{
if(!root)
{
return;
}
remove_all(root->children);
delete root;
}
Obviously neither of these are working or I wouldn't be here :).
Other question. Do I have to call the remove_all function in my main function if my destructor is implemented like this
PrefixStringSet::~PrefixStringSet()
{
remove_all(root);
}
Or does the destructor automatically delete the trees/nodes I create?
Edit
struct TrieNode
{
TrieNode(bool present = false);
bool is_leaf();
bool present;
TrieNode* children[ALPHABET_SIZE];
};
class PrefixStringSet
{
public:
// Creates an empty prefix string set.
PrefixStringSet();
~PrefixStringSet();
bool insert(string s);
bool contains(string s);
private:
NodePtr root;
void remove_all(NodePtr node);
};
typedef TrieNode* NodePtr;
Deleting only root is not enough: when deleting a root, you should check whether its children aren't empty, and if they are not empty, recursively delete them. C++ doesn't have garbage collector to do the work for you :)
If your remove_all method is within the destructor of the wrapper object, then you don't have to call it separately.
You should write a remove method in all classes you want to delete at runtime.
So you can delete a tree with little care about garbage collection.
It's easy to use pointer in this way:
class a
{
public:
a(){}
~a(){remove();}
init(int v){
var = new int;
*var=v; }
remove(){delete var;}
private:
int *var;
};
class b
{
public:
b(){}
~b(){remove();}
init(int v){
var = new a;
var->init(v); }
remove(){
var->remove();
delete var; }
private:
a *var;
};
To answer your question: No, deleting root is not enough.
edit: sry i made a mistake at a:init(). I forgot to derefer the pointer.
In Cpp:
void deleteAll(Node* curNode) {
for (int i = 0; i < 26; i++) {
if (NULL != curNode->child[i]) {
deleteAll(curNode->child[i]);
}
}
delete curNode;
}
deleteAll(root);
I've created class for building a linked list. The class declaration is as follows:
class LinkedList
{
private:
int data;
LinkedList *next;
static int count;
public:
LinkedList(void);
~LinkedList(void);
int insert(int arg);
int remove(int arg);
bool find(int arg);
};
How can I make sure all nodes of this linked list are deleted? The destructor is made responsible for deleting just one node. I used to make linked list like this previously but never thought about clearing the memory.
The naive implementation
~LinkedList() {delete next;}
will do the right thing - delete will call the destructor on the next element, which will delete the one following it, and so on, to delete the whole list.
However, this means that the destructors are called recursively, so that deleting a very long list could cause a stack overflow. Iteration might be better:
~LinkedList() {
while (LinkedList * head = next) {
next = head->next;
head->next = nullptr;
delete head;
}
}
As noted in the comments, it might be more appropriate to have separate List and Node classes, with List responsible for memory management, and Node a simple aggregate containing the data and the link. Then there's less scope for error in the destructor, as it doesn't need to nullify any pointers to prevent recursion:
struct Node {
int data;
Node * next;
};
struct List {
Node * head;
~List() {
while (Node * victim = head) {
head = victim->next;
delete victim;
}
}
};
I am trying to write a node deletion for a binary tree. These are my node and tree structures:
class node{
public:
int value;
node* left;
node* right;
~node();
};
class tree{
public:
node* root;
....
};
And this is the function I wrote:
void tree::del(node** r, int x){
if(*r)
{
if((*r)->value==x)
{
if(!(*r)->left)
*r= (*r)->right;
else if(!(*r)->right)
*r= (*r)->left;
else
{
int k= delMax((*r)->left);
(*r)->value= k;
}
}
else if((*r)->value > x)
{
node* k= (*r)->left;
del(&k, x);
}
else
{
node* k= (*r)->right;
del(&k, x);
}
}}
My problem is that once I get to the desired element, the pointers change but then when the tree is rebuilt recursively it goes back to what it was originally and no element is deleted. I thought passing a pointer to the pointer would solve this but it didn't. delMax deletes the maximum element from the tree and it works correctly on its own.
Also, in the destructors for the last two classes, how should I place the deletes? because if I just put delete right; delete left; in ~node() and delete root in ~tree() I get an error that I'm corrupting the heap.
Thanks!
By making a local variable k and passing its address, the assignments through *r affect the local variable rather than any pointer in the tree.
As an aside, writing node *&r might save you several & and *s.