0

I'm beginner in Python and I tried to create a function to delete a node in a binary search tree.

I tried calling .delete on a node. The node is a leaf node with no children so it should be deleted. However, after I called .delete, the node is still there.

This is the code:

class Node:
    def __init__(self,key): 
        self.left = None
        self.right = None
        self.val = key 

    #some functions for insert etc.

    def delete(self, key):
        """DELETE"""
        try:
            if self is None:
                print("Tree is empty.")
                return None
            else:
                if key < self.val: 
                    self.left.delete(key) 

                elif key > self.val: 
                    self.right.delete(key)

                else: 
                    #this seems to be the problem
                    if self.left is None : 
                        temp = self.right
                        #print(self, self.val, self.right)
                        self = temp
                        return

                    elif self.right is None : 
                        temp = self.left  
                        self = temp
                        return  

                    temp = minValue(self.right)  
                    self.val = temp.val 

                    self.right.delete(temp.val) 
        except(AttributeError):
            print("There's no such number in a tree.")


def inorder(root):
    if root is not None: 
        inorder(root.left) 
        print(root.val, end=" ") 
        inorder(root.right) 


def minValue(node): 
    current = node  
    while(current.left is not None): 
        current = current.left    
    return current

r = Node(50)

After inserting numbers 30 20 40 70 60 80 to r and calling inorder(r) I get: 20 30 40 50 60 70 80, which corresponds to the tree

      50 
    /    \ 
   30     70 
  /  \   /  \ 
 20  40 60  80 

but after r.delete(30), I get: 20 40 40 50 60 70 80, which is:

      50 
    /    \ 
   40     70 
  /  \   /  \ 
 20  40 60  80 

The value to delete is replaced correctly but the used node (40) without children should be deleted.

What may be the reason of such a problem?

1 Answer 1

1

Simply put, you cannot assign anything to self. In Python, self is a reference to the object that you called the method on. It would not be None (so you don't need the if self is None check), and you cannot assign some other value to it.

However, when deleting a node from the tree, it is possible that the current node (the node which you called delete on) will be deleted. Instead of assigning values to self, we can make the delete return a node object. If the current node is not deleted, simply return itself; otherwise, return the node the will take its place (or None if the entire subtree is gone).

Here's the modified implementation, along with an insert method and a test case:

class Node:
    def __init__(self, key):
        self.left = self.right = None
        self.val = key

    def delete(self, key):
        """Delete a node with value `key`."""
        if key < self.val: 
            # Find and delete the value in the left subtree.
            if self.left is None:
                # There's no left subtree; the value does not exist.
                raise ValueError("Value not found in tree")
            self.left = self.left.delete(key)
            return self  # current node not deleted, just return
        elif key > self.val: 
            # Find and delete the value in the right subtree.
            if self.right is None:
                # There's no right subtree; the value does not exist.
                raise ValueError("Value not found in tree")
            self.right = self.right.delete(key)
            return self  # current node not deleted, just return
        else:
            # The current node should be deleted.
            if self.left is None and self.right is None:
                # The node has no children -- it is a leaf node. Just delete.
                return None

            # If the node has only one children, simply return that child.
            if self.left is None:
                return self.right
            if self.right is None:
                return self.left

            # The node has both left and right subtrees, and they should be merged.
            # Following your implementation, we find the rightmost node in the
            # left subtree and replace the current node with it.
            parent, node = self, self.left
            while node.right is not None:
                parent, node = node, node.right
            # Now, `node` is the rightmost node in the left subtree, and
            # `parent` its parent node. Instead of replacing `self`, we change
            # its attributes to match the value of `node`.
            if parent.left is node:
                # This check is necessary, because if the left subtree has only
                # node, `node` would be `self.left`.
                parent.left = None
            else:
                parent.right = None
            self.val = node.val
            return self

    def insert(self, key):
        if key < self.val:
            if self.left is None:
                self.left = Node(key)
            else:
                self.left.insert(key)
        else:
            if self.right is None:
                self.right = Node(key)
            else:
                self.right.insert(key)

def inorder_traverse(node):
    if node is None:
        return []
    ret = []
    if node.left is not None:
        ret += inorder_traverse(node.left)
    ret.append(node.val)
    if node.right is not None:
        ret += inorder_traverse(node.right)
    return ret

values = [5, 1, 2, 7, 3, 6, 4]
root = Node(values[0])
for x in values[1:]:
    root.insert(x)
print(inorder_traverse(root))

for x in values:
    root = root.delete(x)
    print(inorder_traverse(root))

The output is, as expected:

[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 6, 7]
[2, 3, 4, 6, 7]
[3, 4, 6, 7]
[3, 4, 6]
[4, 6]
[4]
[]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.