Destructor for Tree Node Class

Destructor Flaticon

Introduction

Creating a Destructor for tree node class is a common practice in programming when dealing with dynamically allocated memory. The destructor is responsible for cleaning up resources and memory associated with a class when an object is no longer in use. In the context of a tree node class, it plays a vital role in preventing memory leaks and maintaining efficient memory management.

In this guide, we will explore “Destructor” class for deleting a node from Binary tree.

The Role of a Destructor for Tree Node Class

A destructor is a special member function in a class that is automatically called when an object of the class goes out of scope or is explicitly deleted. Its primary purpose is to release any resources, such as dynamically allocated memory, that the class may have acquired during its lifetime.

For tree node classes, the destructor plays a crucial role in:

Deleting node using Destructor class Example

Consider a Binary Tree : Let us take an example.

Destructor Example

In the ‘BinaryTreeNode’ class, a destructor function is declared to handle the cleanup of a tree node. When the ‘delete’ keyword is applied to an object of this class, it initiates the removal of the entire binary tree, and the object’s destructor is invoked.

  • The ‘delete’ keyword is used on the children nodes, triggering their respective destructors one by one.
  • This process continues recursively until the entire binary tree is deleted.
  • Consider the tree above: when the destructor is called for the root node ’13’, it, in turn, invokes the destructors for 11′ and ’15’. Node ’11’ further calls the same process for its left and right children with data ‘9’ and ’12’.
  • Ultimately, the tree is deleted in a specific order: 9 -> 12 ->11 -> 15 -> 13 (following a post-order traversal).

Prime Course Trailer

Related Banners

Get PrepInsta Prime & get Access to all 200+ courses offered by PrepInsta in One Subscription

Implementation of Destructor for Tree Node Class

In Python, you don’t need to explicitly define destructors like you do in C++. Python has a garbage collector that automatically reclaims memory when objects are no longer referenced. However, if you want to perform cleanup or specific actions when an object is deleted, you can define a special method called “__del__”.

Code :

Run
class TreeNode:
    def __init__(self, value):
        self.data = value
        self.left = None
        self.right = None

    def __del__(self):
        # Optionally, you can perform cleanup actions here
        print(f"Deleted node with data: {self.data}")

# Creating a binary tree
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)

# Deleting the root node will trigger the __del__ method, leading to a recursive "deletion" of the entire tree
del root

Output :

Deleted node with data: 4
Deleted node with data: 5
Deleted node with data: 2
Deleted node with data: 3
Deleted node with data: 1

Explanation :

In the provided Python code, a binary tree of “TreeNode” objects is created. The “__del__” method, defined within the class, is responsible for performing custom cleanup when an object is deleted. Upon deleting the root node, the “__del__” method is called recursively for all nodes in a post-order manner. As each node is deleted, a message indicating its data is printed, illustrating the orderly deletion of the tree’s nodes.

Time and Space Complexity:

OperationTime ComplexitySpace Complexity
Node CreationO(1) per nodeO(1) per node
Tree Construction (n nodes)O(n)O(n)
Tree Deletion using `del root`O(n)O(h)

BST Destructor without Recursion

In Python, you can achieve a non-recursive destructor for a binary search tree (BST) using an iterative approach. Here’s an example of a BST destructor in Python without recursion:

Code :

Run
class TreeNode:
    def __init__(self, value):
        self.data = value
        self.left = None
        self.right = None

def destroy_bst(root):
    if not root:
        return

    stack = []
    current = root

    while stack or current:
        if current:
            stack.append(current)
            current = current.left
        else:
            current = stack.pop()
            # Optionally, perform any cleanup or custom logic here
            print(f"Deleted node with data: {current.data}")
            # Explicitly remove the node to avoid re-visiting it
            current = None
            current = current.right

def main():
    # Creating a binary search tree
    root = TreeNode(3)
    root.left = TreeNode(1)
    root.right = TreeNode(5)
    root.left.right = TreeNode(2)
    root.right.left = TreeNode(4)

    # Deleting the entire BST using the non-recursive destructor
    destroy_bst(root)

if __name__ == "__main__":
    main()

Output:

Deleted node with data: 1
Deleted node with data: 2
Deleted node with data: 4
Deleted node with data: 5
Deleted node with data: 3

Explanation :

The Python code illustrates a non-recursive destructor for a binary search tree (BST). Using an iterative approach with a stack, it simulates an in-order traversal of the tree while deleting nodes. Messages are printed for each deleted node, showcasing the order of deletion. This approach allows for efficient destruction of the BST without the use of recursion, demonstrating a key principle in data structure management.

Time and Space Complexity:

OperationTime ComplexitySpace Complexity
Node CreationO(1) per nodeO(1) per node
Tree Construction (n nodes)O(n)O(n)
Tree Deletion using Iterative InorderO(n)O(h)

Usage and Best Practices

When working with tree node classes, here are some best practices for using destructors:

  • Ensure that a destructor is defined if your class acquires resources that need cleanup.
  • Implement the destructor to perform proper resource deallocation, such as releasing memory or closing handles.
  • If you have custom resources in your class, make sure they are properly cleaned up in the destructor.
  • Avoid manual memory leaks by employing the destructor to handle dynamically allocated memory.
  • Be cautious with circular references in the tree structure to prevent infinite recursion in the destructor.

To Wrap it up: 

In summary, creating a destructor for a tree node class is a crucial step in proper memory management and resource cleanup. It helps prevent memory leaks, ensures efficient memory usage, and contributes to the overall reliability and performance of software utilizing tree data structures.

FAQs

A destructor is used to free up the memory allocated for the tree nodes to avoid memory leaks. It ensures that when a tree is deleted, all its nodes are properly deallocated.

In Python, destructors can be defined using the __del__ method. However, manual deletion using post-order traversal is preferred to ensure all child nodes are deleted before the parent.

Post-order ensures that a node’s left and right children are deleted before the node itself. This prevents accessing deleted memory and ensures proper cleanup.

No, del only decreases the reference count of an object. For complete deletion, all references to child nodes must also be explicitly removed or recursively handled.

Get over 200+ course One Subscription

Courses like AI/ML, Cloud Computing, Ethical Hacking, C, C++, Java, Python, DSA (All Languages), Competitive Coding (All Languages), TCS, Infosys, Wipro, Amazon, DBMS, SQL and others

Checkout list of all the video courses in PrepInsta Prime Subscription

Checkout list of all the video courses in PrepInsta Prime Subscription