Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在python中实现二叉搜索树删除时遇到问题_Python_Binary Search Tree - Fatal编程技术网

在python中实现二叉搜索树删除时遇到问题

在python中实现二叉搜索树删除时遇到问题,python,binary-search-tree,Python,Binary Search Tree,我实现了一个二叉搜索树的删除功能。其思想是声明一个私有函数,该函数使用一个额外的参数将self.root提取到root。在私有删除功能中,它将执行条件检查,并确保root等于需要删除的数据。在条件检查之后,我写下3种不同的删除情况。编译代码时没有错误消息,也没有删除任何插入的节点 class Node(object): def __init__(self, data, left=None, right=None, parent=None): self.left = lef

我实现了一个二叉搜索树的删除功能。其思想是声明一个私有函数,该函数使用一个额外的参数将
self.root
提取到
root
。在私有删除功能中,它将执行条件检查,并确保
root
等于需要删除的数据。在条件检查之后,我写下3种不同的删除情况。编译代码时没有错误消息,也没有删除任何插入的节点

class Node(object):
    def __init__(self, data, left=None, right=None, parent=None):
        self.left = left  
        self.data = data
        self.right = right   


class Tree(object):
    def __init__(self):
        self.root = Node(None)

    def delete(self,newData):
        if self.root.data == None:
            print 'The tree is empty'
        else:
            self.__delete(self.root, newData)

    def __delete(self, root, newData):
        # if newData smaller than root.data, change root to root.left, recursive call
        if newData < root.data:
            if root.left:
                self.__delete(root.left, newData)
            else:
                return False
        # if newData larger than root.data, change root to root.right, recursive call
        elif newData > root.data:
            if root.right:
                self.__delete(root.right, newData)
            else:
                return False
        elif newData == root.data:
            #case 1, root has no child
            if root.left is None and root.right is None:
                root = None
            #case 2, root has one child (left)
            elif root.left is not None and root.right is None:
                root.data = root.left.data
                root.left = None
            #case 3, root has one child (right)
            elif root.right is not None and root.left is None:
                root.data = root.right.data
                root.right = None
            #case 4, root has both children,
            # find the smallest node in the right subtree, and swipe value
            # delete smallest node in the right subtree
            else:
                root.data = self.__minValueToRightSubtree(root.right).data
                self.__deleteMinValueToRightSubtree(root.right)
        else:
            print "Can't find this number"

    def __minValueToRightSubtree(self, root):
        if root.left is None:
            return root
        else:
            return self.__minValueToRightSubtree(root.left)

    def __deleteMinValueToRightSubtree(self, root):
        if root.left is None:
            root = None
            return root
        else:
            self.__minValueToRightSubtree(root.left)
类节点(对象):
def uuu init uuuu(self,data,left=None,right=None,parent=None):
self.left=左
self.data=数据
self.right=right
类树(对象):
定义初始化(自):
self.root=节点(无)
def delete(自我,新数据):
如果self.root.data==无:
打印“树为空”
其他:
self.\u删除(self.root,newData)
定义删除(self、root、newData):
#如果newData小于root.data,则将root更改为root.left,递归调用
如果newDataroot.data:
如果root.right:
self.\u delete(root.right,newData)
其他:
返回错误
elif newData==root.data:
#案例1,root没有子级
如果root.left为无,root.right为无:
根=无
#案例2,根目录有一个子目录(左)
elif root.left不是无,root.right是无:
root.data=root.left.data
root.left=无
#案例3,root有一个子级(右)
elif root.right不是None,root.left是None:
root.data=root.right.data
root.right=None
#案例4,root有两个孩子,
#在右子树中找到最小的节点,然后滑动值
#删除右子树中最小的节点
其他:
root.data=self.\uu minValueToRightSubtree(root.right).data
self.\uu删除MinValueToRightSubtree(root.right)
其他:
打印“找不到此号码”
def__minValueToRightSubtree(self,root):
如果root.left为无:
返回根
其他:
返回self.\uu minValueToRightSubtree(root.left)
def _deleteMinValueToRightSubtree(self,root):
如果root.left为无:
根=无
返回根
其他:
self._minValueToRightSubtree(根.左)

不幸的是,递归函数的基本情况都不能正常工作。有两种错误(每种错误重复两次,但有一些变化):

第一个问题相当简单。在案例2和案例3中,您从单个子节点复制数据,然后删除对该节点的引用。但是,如果子节点有自己的子节点,那么这样做是不对的。如果你的树保证是平衡的,也许你可以假设它没有子树,但是对于一般的BST,你不能这样假设。更好的版本是:

        #case 2, root has one child (left)
        elif root.left is not None and root.right is None:
            root.data = root.left.data
            root.right = root.left.right
            root.left = root.left.left
        #case 3, root has one child (right)
        elif root.right is not None and root.left is None:
            root.data = root.right.data
            root.left = root.left.left
            root.right = root.left.right
另一个问题更微妙。问题是,在案例1(以及案例4中的
\u deleteMinValueToRightSubtree
帮助程序方法)中,您无法以尝试的方式删除
根目录。您将<代码> NOT/CONT>分配给<代码>根<代码>,如果Python以C++和java DO(通过引用)的方式传递参数,则这可能会起作用。但是Python的参数与这些语言不同。Python参数是“通过赋值”传递的,这意味着函数中的参数是一个局部变量,绑定到调用方传入的同一对象。如果执行
root=None
,则只修改局部变量,而不是树结构

有多种方法可以解决此问题。哪种方式最好将取决于实现的其他细节

如果
节点
对象具有
父节点
引用,则可以使用这些引用来取消节点与其父节点的链接(尽管对于没有父节点的根节点,您需要特殊情况)。我看到
节点的
构造函数有一个
parent
参数,但您似乎没有使用它。如果将其连接起来,则删除节点的代码将相对容易

        #case 1, root has no child
        if root.left is None and root.right is None
            if root.parent is None: # root is the root node of the whole tree
                self.root = None
            elif root.parent.left is root:
                root.parent.left = None
            else: # elif root.parent.right is root:
                root.parent.right = None
        #...
        #case 4, root has both children,
        # find the smallest node in the right subtree, and swipe value
        # delete smallest node in the right subtree
        else:
            min_right_node = self.__minValueToRightSubtree(root.right)
            root.data = min_right_node.data       # no need to recurse twice
            if min_right_node is self.right:      # we can use the same node reference for
                self.right = None                 # both steps (swiping value and deleting)
            else:
                min_right_node.parent.left = min_right_node.right
如果没有父链接,则可以改为更改递归的逻辑,以便
返回修改后的树,调用者将该树分配给它正在递归的节点。这将要求您更改错误处理,因为返回值不是用于表示成功或失败的信号。如果找不到目标,我建议引发异常

def delete(self,newData):
    if self.root.data == None: # should this be testing `self.root is None`?
        print 'The tree is empty'
    else:
        self.root = self.__delete(self.root, newData) # use return value

def __delete(self, root, newData):
    # if newData smaller than root.data, change root to root.left, recursive call
    if newData < root.data:
        if root.left:
            root.left = self.__delete(root.left, newData)
        else:
            raise ValueError("Can't find this number")
    # if newData larger than root.data, change root to root.right, recursive call
    elif newData > root.data:
        if root.right:
            root.right = self.__delete(root.right, newData)
        else:
            raise ValueError("Can't find this number")
    elif newData == root.data:
        #case 1, root has no child
        if root.left is None and root.right is None:
            return None
        #case 2, root has one child (left)
        elif root.left is not None and root.right is None:
            return root.left
        #case 3, root has one child (right)
        elif root.right is not None and root.left is None:
            return root.right
        #case 4, root has both children,
        # find the smallest node in the right subtree, and swipe value
        # delete smallest node in the right subtree
        else:
            root.right, root.data = __delete_min(root.right)
            return root
    else:
        print "Can't find this number"

def __delete_min(self, root): # returns a (node, minimum value) 2-tuple
    if root.left is None:
        return root.right, root.data
    else:
        root.left, minval = self.__delete_min(root.left)
        return root, minval
def delete(self,newData):
如果self.root.data==None:#这应该是在测试“self.root是None”吗?
打印“树为空”
其他:
self.root=self.u删除(self.root,newData)#使用返回值
定义删除(self、root、newData):
#如果newData小于root.data,则将root更改为root.left,递归调用
如果newDataroot.data:
如果root.right:
root.right=self.\u删除(root.right,newData)
其他:
raise VALUE ERROR(“找不到此号码”)
elif newData==root.data:
#案例1,root没有子级
如果root.left为无,root.right为无:
一无所获
#案例2,根目录有一个子目录(左)
elif root.left不是None,root.right是No