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);
Related
I'm trying to write class for binary tree in c++ but I think in inserting function I have some problem it doesnt work correctly I'm begginer in c++ and I can't find the problem.
I should write this code without using "struct" it should Compeletly write with classes
I'm so sorry beacuse my code doesn't have any comment
and also sorry for bad English
Thank you very much
#include<iostream>
using namespace std;
///////////////////////////////////////////////////////////////////////////
class Tree
{
public:
Tree* left;
Tree* right;
string info;
Tree()
{
this->left=NULL;
this->right=NULL;
this->info="";
}
Tree(string info)
{
this->left=NULL;
this->right=NULL;
this->info=info;
}
Tree(string info,Tree* left,Tree* right)
{
this->left=left;
this->right=right;
this->info=info;
}
};
/////////////////////////////////////////////////////////////////////
class LinkedList
{
public:
Tree* root;
LinkedList()
{
root=NULL;
}
void mainInsert(Tree* newroot , string info)
{
if(newroot==NULL)
{
Tree* newNode = new Tree(info);
newroot=newNode;
return;
}
if(info.compare(newroot->info)==-1)
{
mainInsert(newroot->left,info);
}
else
{
mainInsert(newroot->right,info);
}
}
void mainPrintTree(Tree* newroot)
{
if(newroot==NULL)
{
return;
}
cout<<newroot->info<<endl;
mainPrintTree(newroot->left);
mainPrintTree(newroot->right);
}
void insert(string info)
{
mainInsert(this->root , info);
}
void printTree()
{
mainPrintTree(this->root);
}
};
///////////////////////////////////////////////////////////////////////////
int main()
{
LinkedList myTree;
myTree.insert("2");
myTree.insert("1");
myTree.insert("3");
myTree.insert("7");
myTree.insert("0");
myTree.printTree();
return 0;
}
Here is a (the?) culprit:
void mainInsert(Tree* newroot, string info)
{
if (newroot == NULL)
{
Tree* newNode = new Tree(info);
newroot = newNode; // Oops, only changing a local pointer here!
return;
}
...
It is a common error of beginners: you passed a pointer to a function, change that pointer and wonder why the original pointer is still unchanged... The reason is that apart from being able to change its pointee value, a pointer is a mere variable. So the function has its local copy of the pointer, and changing it has no effect in the caller. Here a simple way is probably to return the new root:
Tree* mainInsert(Tree* newroot, string info)
{
if (newroot == NULL)
{
Tree* newNode = new Tree(info);
return newNode;
}
// remember to return newroot in other branches...
Just use that in insert:
void insert(string info)
{
this->root = mainInsert(this->root , info);
}
But there are tons of possible improvements here, like separating the public interface from the private implementation, so I would advise you to post your code on Code Review as soon as is will work without errors...
Your mainInsert is wrong: after mainInsert(newroot->left,info);, newroot->left is not modified because that argument is passed by value (BTW read this SO article article, it's about C, not C++ but the concept is the same).
The simplest here is just to pass the node by reference, which makes your code even simpler:
void mainInsert(Tree* &subTree, string info)
{
if (subTree == NULL)
{
subTree = new Tree(info);
return;
}
if (info.compare(subTree->info) == -1)
{
mainInsert(subTree->left, info);
}
else
{
mainInsert(subTree->right, info);
}
}
I renamed the newroot parameter into subTree, because there is actually only one root per tree and every node of the tree is actually a also tree.
BTW: your question about writing this code without using struct is pointless, you don't use struct at all in your code.
Hint: try to write an iterative version of mainInsert. It's pretty simple and straightforward as the problem is not inherently recursive.
I'm trying to implement a class of Circular List with a nested class of iterator and I wrote like this:
template <class T>
class CircularList {
struct Item {
T data;
Item* next;
};
Item* head;
int size;
public:
CircularList() {
head = new Item();
head->next = head;
}
int sizeList() { return size; }
void push(T data) {
Item* i = new Item();
i->data = data;
i->next = head->next;
head->next = i;
size++;
}
class CircularListIterator {
Item* p;
CircularListIterator() {
p = head->next;
}
bool hasNext() {
if(p->next != head) {
return true;
}
return false;
}
T next() {
T data_temp = p->data;
p = p->next;
return data_temp;
}
};
CircularListIterator* iterator() {
return new CircularListIterator();
}
};
int main() {
CircularList<string>* letters = new CircularList<string>;
letters->push("d");
letters->push("c");
letters->push("b");
letters->push("a");
Iterator<string>* it= new Iterator<string>;
it = letters->iterator();
while (it->hasNext()) {
cout<< it->next() << "," << endl;
}
return 0;
}
But the Iterator is not working when I try to create an iterator in the main function, It said that it wasn't declared in the scope and has no member of it.
Assuming by "in the main class" you mean in the main function, the problem is quite straightforward: you're trying to construct a ::Iterator<string>, but there is no class in the global namespace (or anywhere else, in this code sample) called Iterator! You could try constructing a CircularList<string>::CircularListIterator - that's at least a class that exists - but it wouldn't work because the iterator needs to be associated with a CircularList object for it to be able to access member variables like head.
The correct thing to do here is to promote the iterator function - the one that returns a CircularListIterator* - out of the CircularListIterator class and into the CircularList class. Then, in your main function, you can call letters->iterator() and it'll return a CircularListIterator* for the letters object.
Now, CircularListIterator doesn't inherit from any other iterator classes - neither the (nonexistent-in-this-code Iterator you've typed it as, nor the C++ std::iterator or any of its variants) - so you can't assign it to it or probably even compile the code that references Iterator. To make CircularListIterator a subclass of std::iterator, you'll need to extend std::iterator<Category, T> with the appropriate category. See https://www.cplusplus.com/reference/iterator/iterator/ for more information on the std::iterator class template, including an example of implementing it.
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.
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 am trying to implement a custom tree structure, but I am getting a weird output.
enum letter{B,A,T,G,C,N};
struct Node {
int ltr;
Node* ptr;
};
class GTree
{
public:
GTree(int);
void insert(int);
private:
Node* root;
void insert(int l,Node* leaf);
};
GTree::GTree(int l)
{
root->ltr=l;
}
void GTree::insert(int l, Node *leaf)
{
cout<<leaf->ltr;
}
void GTree::insert(int l)
{
if(root==NULL)
{
insert(l, root);
}
else
{
root= new Node;
insert(l,root);
}
}
int main()
{
GTree tree=GTree(T);
tree.insert(T);
}
The output comes out as -2062064467 even though I was expecting 2. Whats going on here? I was looking at a simple BTree implementation, but intending to repurpose it for my desired data structure.
You didn't create a Node object when you first created the GTree object.
GTree::GTree(int l)
{
root->ltr=l;
}
should be
GTree::GTree(int l)
{
root = new Node();
root->ltr=l;
}
Also, make sure you have a destuctor to clean up the resources.
Something else I feel I should point out is that GTree::insert(int l, Node *leaf) perhaps doesn't do what you expect it to do.
cout<<leaf->ltr;
The code above only outputs the integer value in the node but not actually assigning it.
But perhaps you haven't completed that part yet. :-)
You hadn't initialized root, so root->ltr=l; produces undefined behavior. Add root = new Node(); first.
I ran your code and got the output 0 on Ubuntu 12.04 with gcc 4.6.3.