我在stackoverflow找到另一个好的线程,将它链接到removing a node from a binary search tree using recursion。这是我从中获取代码的地方,它看起来像这样:
import random
from time import time
class BinaryNode:
def __init__(self, value = None):
"""Create binary node"""
self.value = value
self.left = None
self.right = None
def add(self, val):
"""Adds a new node to the tree containing this value"""
if val <= self.value:
if self.left:
self.left.add(val)
else:
self.left = BinaryNode(val)
else:
if self.right:
self.right.add(val)
else:
self.right = BinaryNode(val)
def delete(self):
"""
Remove value of self from BinaryTree. Works in conjunction with remove
method in BinaryTree
"""
if self.left == self.right == None:
return None
if self.left == None:
return self.right
if self.right == None:
return self.left
child = self.left
grandchild = child.right
if grandchild:
while grandchild.right:
child = grandchild
grandchild = child.right
self.value = grandchild.value
child.right = grandchild.left
else:
self.left = child.left
self.value = child.value
return self
class BinaryTree:
def __init__(self):
"""Create empty binary tree"""
self.root = None
def add(self, value):
"""Insert value into proper location in Binary Tree"""
if self.root is None:
self.root = BinaryNode(value)
else:
self.root.add(value)
def contains(self, target):
"""Check whether BST contains target value"""
node = self.root
while node:
if target == node.value:
return True
if target < node.value:
node = node.left
else:
node = node.right
return False
def remove(self, value):
"""Remove value from tree"""
if self.root:
self.root = self.removeFromParent(self.root, value)
def removeFromParent(self, parent, value):
"""remove value from tree rooted at parent"""
if parent is None:
return None
if value == parent.value:
return parent.delete()
elif value < parent.value:
parent.left = self.removeFromParent(parent.left, value)
else:
parent.right = self.removeFromParent(parent.right, value)
return parent
如果我们专注于delete
类下的BinaryNode
方法,我需要一些帮助来理解指针,我之前已经将我自己的二进制搜索树放在一起,但我无法理解,是{{1}一个指针?什么是self.left
(见self.left.right
),这是一个从“开始”的指针,很快就是根,到孩子,然后到右边(到孙子)。对我来说,grandchild
方法不需要删除哪个值的参数,我觉得有点奇怪,我在其他任何地方都看不到使用该方法......
答案 0 :(得分:1)
左和右属性是对象。实际上,它们被实现为对象引用,a.k.a。指针。
self.left.right是 self (你的临时“root”)的左右孙子。 **自我*最多可以有四个grandchlidren;这是第二个(从左到右计数),左孩子的右孩子。
删除确实有一个参数: self 。这就是它如何知道要删除的节点。该方法未在别处使用,因为其他方法都不需要删除节点。你正在开发一个从外面使用的类,而不是一个自给自足的应用程序。
这能够很好地回答你目前的困惑吗?尝试用铅笔绘制树 - 并完成方法。在单步执行代码时擦除和重绘指针。也许更好,使用两种颜色,因此你有“之前”和“之后”指针,并在你进行时对这些变化进行编号。
我不会说 self 充当前哨节点; “哨兵”概念更多的是停止特定点的迭代。
至于指针/对象二分法,我怀疑你遇到麻烦的原因之一是Python不会让你经常分开这两者。每个变量值都是对变量对象的引用。
具体来说,self.right.left最终是孙子的引用。但是,Python运行时系统使用它来直接访问孙子对象。换句话说,你无法真正区分它们。无论如何都要想到它;在适合您的目的时进行更改(例如抓住左字段,就像它是一个对象一样,然后重置左,就好像它是一个指针)。 Python使这成为一种量子态:波和粒子。
免责声明: 最终会使用熟悉的星号传递参数,以获取指向某些内容的指针,例如* my_list。在这种情况下,你做有明显的区别......但Python会将波函数折回到粒子ASAP。现在不要担心,只要知道它会在晚些时候出现,所以你不要对你在那一点上学到的东西失去信心。