I have a function that creates a binary tree(*build_tree)* (Huffman).
I also need a function that free's the memory that build tree allocated.
It's my first time working with binary trees so I'm kind of confused.
Should I create a loop that goes through each node in the tree and deletes it?
Should I consider if the node is a leaf or a parent node?
void free_memory(NodePtr root)
{
delete root;
}
struct HuffmanNode
{
//some stuff
HuffmanNode *left;
HuffmanNode *right;
};
Would appreciate it if someone could help me get started :)
If you use smart pointers the problem will solve itself. If each node contains a private SP to it's children and you delete a node all it's children will also be freed. Obviously your class destructor, which will get called by the SP when it cleans up will need to free any other non RIIA allocated resources if any exist.
class Node
{
private:
std:unique_ptr<Node> left;
std:unique_ptr<Node> right;
}
I'm using std::unique_ptr<> here because I'm assuming that these are private and not exposed to other parts of your program. If you want other things to reference nodes using these pointers then you should use std::shared_ptr<>.
If you're not using SP then the class destructor needs to do the work itself and you have to be much more careful about memory leaks. Each class destructor deletes its children, which in turn will call the destructor in each child.
class Node
{
private:
NodePtr left;
NodePtr right;
~Node()
{
delete left;
delete right;
// Delete any other resources allocated by the node.
}
}
You can also do as #OldProgrammer suggests and traverse the tree bottom up deleting nodes as you go. Remember you have to do this bottom up. If you did it top down then you would loose the reference to the (as yet) undeleted child nodes and leak memory. As you can see the code for recursive deletion (as referenced in #unluddite's answer) is a lot more complex.
There is a memory overhead for doing (anything) recursively. See: Is a recursive destructor for linked list, tree, etc. bad?. If your tree is very large then you should consider this and test accordingly.
My recommendation would be for the first solution if you are OK with using SP.
If you implement a post-order tree traversal and delete the node and data at the process step, you will ensure that each node of your tree is visited and the data deleted.
You can see a recursive and iterative example here with the relevant code reproduced below.
Recursive solution:
void postOrderTraversal(BinaryTree *p) {
if (!p) return;
postOrderTraversal(p->left);
postOrderTraversal(p->right);
// this is where we delete
delete p->data;
delete p;
}
One possible iterative solution:
void postOrderTraversalIterative(BinaryTree *root) {
if (!root) return;
stack<BinaryTree*> s;
s.push(root);
BinaryTree *prev = NULL;
while (!s.empty()) {
BinaryTree *curr = s.top();
if (!prev || prev->left == curr || prev->right == curr) {
if (curr->left)
s.push(curr->left);
else if (curr->right)
s.push(curr->right);
} else if (curr->left == prev) {
if (curr->right)
s.push(curr->right);
} else {
// this is where we delete
delete curr->data;
delete curr;
s.pop();
}
prev = curr;
}
}
Related
Why we initialize the next pointer of Linked List as NULL before deletion
we move our head to the next node during deletion and we free the memory of the first node, so why we need to initialize the next pointer of deleted node as NULL before deletion.
without it, the code runs without any issues.
Is this dangling pointer will create a issue? please throw some light in it
class Node
{
public:
int data;
Node* next;
Node(int d) //construtor for storing the value in nodes
{
this->data=d;
this->next=NULL;
}
};
void DeleteAt(int position,Node* &head,Node *&tail)
{
if(position ==1)
{
Node* temp=head;
head=temp->next;
temp->next=NULL;
delete temp;
}
else
{
Node *curr=head;
Node *prev=NULL;
int cnt=1;
while(cnt<position)
{
prev=curr;
curr=curr->next;
cnt++;
}
// if delete at tail is called ,for updation of tail,
//if required
if(curr->next==NULL)
{
tail=prev;
}
prev->next=curr->next;
curr->next=NULL;
delete curr;
}
}
You don't need to do this, it's just to help you while you're learning. It's common for teachers to do this to help avoid use-after-frees. This way, it's much more obvious you have a problem, because if you accidentally try to use the node you just deleted, you'll probably get a segfault.
Hi I read this logic over internet and tried implementing the level order tree traversal in c++
void levelorder(struct node* root)
{
struct node* temp = (struct node*)malloc(sizeof(struct node));
std::queue<node*> qq;
if(root==NULL)
{
return;
}
qq.push(root);
while(!qq.empty())
{
temp=qq.front();
qq.pop();
printf("%d",temp->data);
qq.push(temp->left);
qq.push(temp->right);
}
}
But the above is giving me an error segmentation fault which I think is happening because
temp->left
does not exist. Or should i need llQueue for this implementation.Anybody has any idea about this ?
Ths posted code does not take into account the null pointers at the leaves of the tree. It can be fixed along these lines:
void levelorder(struct node* root)
{
std::queue<node*> qq;
qq.push(root);
while(!qq.empty())
{
struct node* node = qq.front();
qq.pop();
if (node) {
printf("%d",temp->data);
qq.push(temp->left);
qq.push(temp->right);
}
}
}
On the other hand, the memory allocation to temp is lost: This space is not freed and, moreover, will leak, as temp is assigned to somethig else.
Two problems:
the memory allocated for temp is leaked and non-necessary
null pointer at leaf nodes not checked
The implementation proposed by #anumi is correct. But I'd prefer this:
void levelorder(struct node* root)
{
if(!root) return;
std::queue<node*> qq;
qq.push(root);
while(!qq.empty())
{
struct node* node = qq.front();
qq.pop();
printf("%d", node->data);
if(node->left) qq.push(node->left);
if(node->right) qq.push(node->right);
}
}
Edit: handle empty tree according to comments.
Your idea seems correct, however this is impossible to tell without knowing the actual data. In your code, it might be possible that the left and right members are NULL or point to undefined locations, which means that following the left or right pointers might result in errors.
EDIT: So I'm an idiot and forgot to SSH my updated .cpp when working with valgrind. Anyways I've updated the code below to represent new changes. Unfortunately I'm still getting some leaking with the stuff below and I'll I'm doing is creating a tree which means somewhere some information is still not being deleted properly.
Here is my destructor for my tree which calls the recursive helper.
//---------------------------- destructor --------------------------------
BinTree::~BinTree() {
makeEmptyHelper(root);
}
//---------------------------- makeEmptyHelper --------------------------------
void BinTree::makeEmptyHelper(Node*& current) {
if (current != NULL) {
makeEmptyHelper(current->left);
makeEmptyHelper(current->right);
delete current->data;
delete current;
current = NULL;
//delete current;
}
}
Here is my node struct:
struct Node {
NodeData* data; // pointer to data object
Node* left; // left subtree pointer
Node* right; // right subtree pointer
};
NodeData is a separate object class that has its own destructor which works properly.
You should delete current before you set it to NULL, not afterwards. In fact, there is no reason to set current to NULL in the first place: the pointer current is passed by value, so updating it has no external effect.
Note that it is legal to delete NULL, but it is a no-op.
I have recently managed to get a stack overflow when destroying a tree by deleting its root 'Node', while the Node destructor is similar to this:
Node::~Node(){
for(int i=0;i<m_childCount;i++)
delete m_child[i];
}
A solution that come up into my mind was to use own stack. So deleting the tree this way:
std::stack< Node* > toDelete;
if(m_root)
toDelete.push(m_root);
while(toDelete.size()){
Node *node = toDelete.top();
toDelete.pop();
for(int i=0;i<node->GetChildCount();i++)
toDelete.push(node->Child(i));
delete node;
}
But in there the std::stack::push() may throw an exception. Is it possible to write an exception free tree destruction? How?
EDIT:
If anybody is interested here is an exception free non-recursive code inspired by the algorithm pointed out by jpalecek:
Node *current = m_root;
while(current){
if(current->IsLeaf()){
delete current;
return;
}
Node *leftMostBranch = current;// used to attach right subtrees
// delete all right childs
for(size_t i=1; i<current->GetChildCount(); i++){
while(!leftMostBranch->Child(0)->IsLeaf())
leftMostBranch = leftMostBranch->Child(0);
delete leftMostBranch->Child(0);
leftMostBranch->Child(0) = current->Child(i);
}
// delete this node and advance to the left child
Node *tmp = current;
current = current->Child(0);
delete tmp;
}
note: Node::IsLeaf() is equivalent to Node::GetChildCount()!=0.
I just had this as an interview question.
And I must admit this is one of the hardest things I had to solve on the fly.
Personally I don't think it's a good question as you may know the trick (if you have read Knuth) in which case it becomes trivial to solve but you can still fool the interviewer into making him/her think you have solved it on the fly.
This can be done assuming that the node stores child pointers in a static structure. If the node stores child pointers in a dynamic structure then it will not work, as you need to re-shape the tree on the fly (it may work but there is no guarantee).
Surprisingly the solution is O(n)
(Technically every node is visited exactly twice with no re-scanning of the tree).
This solution uses a loop (so no memory usage for stack) and does not dynamically allocate memeroy to hold nodes that need to be deleted. So it is surprisingly effecient.
class Node
{
// Value we do not care about.
int childCount;
Node* children[MAX_CHILDREN];
};
freeTree(Node* root)
{
if (root == NULL)
{ return;
}
Node* bottomLeft = findBottomLeft(root);
while(root != NULL)
{
// We want to use a loop not recursion.
// Thus we need to make the tree into a list.
// So as we hit a node move all children to the bottom left.
for(int loop = 1;loop < root->childCount; ++loop)
{
bottomLeft->children[0] = root->children[loop];
bottomLeft->childCount = std::max(1, bottomLeft->childCount);
bottomLeft = findBottomLeft(bottomLeft);
}
// Now we have a root with a single child
// Now we can delete the node and move to the next node.
Node* bad = root;
root = root->children[0];
delete bad; // Note the delete should no longer destroy the children.
}
}
Node* findBottomLeft(Node* node)
{
while((node->childCount > 0) && node->children[0] != NULL))
{ node = node->children[0];
}
return node;
}
The above method will work as long as their is always a children[0] node (even if it is NULL). As long as you do not have to dynamically allocate space to hold children[0]. Alternatively just add one more pointer to the node object to hold the delete list and use this to turn the tree into a list.
This is what all garbage collectors struggle with. However, the best thing you can do (IMHO) is to pray for enough memory for the stack, and your prayers will be heard 99.99999% of the time. Should it not happen, just abort().
BTW if you are interested, there is a solution to traverse long (and deep) trees without allocating much memory.
Why is the original code throwing an exception? I'm guessing you are doing something like using the same node object in multiple places in the tree. Stack overflows are rarely caused by normal expected situations. Stack overflows are not a problem, they are the symptom of a problem.
Rewriting the code differently won't fix that; you should just investigate & fix the error.
Is it possible to write an exception free tree destruction? How?
Perhaps this (untested code):
void destroy(Node* parent)
{
while (parent)
{
//search down to find a leaf node, which has no children
Node* leaf = parent;
while (leaf->children.count != 0)
leaf = leaf->chilren[0];
//remember the leaf's parent
parent = leaf->parent;
//delete the leaf
if (parent)
{
parent->children.remove(leaf);
}
delete leaf;
} //while (parent)
}
I have a BST which is a linked list in C++. How would I delete the whole thing from memory? Would it be done from a class function?
Just delete the children:
struct TreeNode {
TreeNode *l, *r, *parent;
Data d;
TreeNode( TreeNode *p ) { l = nullptr; r = nullptr; parent = p; }
TreeNode( TreeNode const & ) = delete;
~TreeNode() {
delete l; // delete does nothing if ptr is 0
delete r; // or recurses if there's an object
}
};
or if you're using unique_ptr or some such, that's not even needed:
struct TreeNode {
unique_ptr< TreeNode > l, r;
TreeNode *parent;
Data d;
TreeNode( TreeNode *p ) { l = nullptr; r = nullptr; parent = p; }
TreeNode( TreeNode const & ) = delete;
~TreeNode() = default;
};
If you have access to the linked list itself, it's a piece of cake:
// Making liberal assumptions about the kind of naming / coding conventions that might have been used...
ListNode *currentNode = rootNode;
while(currentNode != NULL)
{
ListNode *nextNode = currentNode->Next;
delete currentNode;
currentNode = nextNode;
}
rootNode = NULL;
If this is a custom implemention of a BST, then this may well be how it works internally, if it has tied itself to a particular data structure.
If you don't have access to the internals, then Potatoswatter's answer should be spot on. Assuming the BST is setup as they suggest, then simply deleting the root node should automatically delete all the allocated memory as each parent down the tree will delete its children.
If you are asking how to go about iterating across a binary tree manually, then you would do the following recursive step:
void DeleteChildren(BSTNode *node)
{
// Recurse left down the tree...
if(node->HasLeftChild()) DeleteChildren(node->GetLeftChild());
// Recurse right down the tree...
if(node->HasRightChild()) DeleteChildren(node->GetRightChild());
// Clean up the data at this node.
node->ClearData(); // assume deletes internal data
// Free memory used by the node itself.
delete node;
}
// Call this from external code.
DeleteChildren(rootNode);
I hope I've not missed the point here and that something of this helps.
Perform a post-order traversal of the tree (i.e. visiting children before parents), and delete each node as you visit it.
Whether or not this has anything to do with classes depends entirely on your implementation.
With the limited information provided ....
If you allocated the nodes with new or malloc (or related functions) than you need to traverse over all the nodes and free or delete them.
An alternative is to put shared_ptr's (and weak_ptr's to kill cyclics) in your allocations -- provided you do it correctly you won't have to free the nodes manually
If you used a quality implementation that you picked up on the internet than provided the classes don't leak, you don't have to worry about anything.
Use smart pointers and forget about it.