所以我有一个二叉搜索树,我试图获得所述树的高度。我有一个self.height属性,每当我执行insert_element(self,value)时递增,并在remove_element(self,value)发生时递减。但是,我注意到,每当其中一种方法出现时,这会递增和递减,并且如果节点处于不会改变高度的相同高度,则不会考虑这种情况。
class Binary_Search_Tree:
class __BST_Node:
def __init__(self, value):
self.value = value
self.lchild = None
self.rchild = None
def __init__(self):
self.__root = None
self.height = 0
def insert_element(self, value):
self._insert(self.__root, value)
def _insert(self, root, value):
node = Binary_Search_Tree.__BST_Node(value)
if root == value:
raise ValueError("Value already exists")
if self.__root is None:
self.__root = Binary_Search_Tree.__BST_Node(value)
self.height += 1
return self.__root
else:
if root.value > node.value:
if root.lchild is None:
root.lchild = node
self.height += 1
return root.lchild
else:
self._insert(root.lchild, value)
elif root.value < node.value:
if root.rchild is None:
root.rchild = node
self.height += 1
return root.rchild
else:
self._insert(root.rchild, value)
return root
def remove_element(self, value):
self.__root = self._remove(self.__root, value)
self.height -= 1
return self.__root
def _remove(self, root, value):
if self.__root is None:
raise ValueError("Tree is empty")
if root.value != value:
raise ValueError("No such value")
if root.value == value:
if root.lchild is None and root.rchild is None:
root = None
self.height -= 1
return root
elif root.lchild is None or root.rchild is None:
if root.lchild is None:
self.height -= 1
return root.rchild
if root.rchild is None:
self.height -= 1
return root.lchild
elif root.lchild and root.rchild:
parent = root
successor = root.rchild
while successor.lchild:
parent = successor
successor = successor.lchild
root.value = successor.value
if parent.lchild == successor:
parent.lchild = successor.rchild
self.height -= 1
return parent.lchild
else:
parent.rchild = successor.rchild
self.height -= 1
return parent.rchild
else:
if root.value > value:
if root.lchild:
root.lchild = self._remove(root.lchild, value)
elif root.value < value:
if root.rchild:
root.rchild = self._remove(root.rchild, value)
return root
def in_order(self):
if self.__root is not None:
self._in(self.__root)
def _in(self, root):
if root is None:
return
if root is not None:
self._in(root.lchild)
print(str(root.value))
self._in(root.rchild)
def get_height(self):
print(str(self.height))
def __str__(self):
return self.in_order()
if __name__ == '__main__':
pass
答案 0 :(得分:0)
以下是您应该完成工作的树的一个版本。 我试图让它与原始代码保持尽可能相似但不得不稍微改变一下,同时试图找出如何使示例工作。
希望它仍然足够接近,让您能够识别关键部件并根据需要重新使用它。
class Binary_Search_Tree:
class __BST_Node:
def __init__(self, value, height):
self.value = value
self.height = height
self.lchild = None
self.rchild = None
def __init__(self):
self.__root = None
self.__height = 0
def _insert(self, knot, value):
if knot is None:
self.__root = Binary_Search_Tree.__BST_Node(value, 1)
result = self.__root
elif knot.value == value:
# replace error with WARNING, to handle exception
# raise ValueError("Value already exists")
print 'WARNING: value', value, 'already exists; skipped'
return knot
elif knot.value > value:
if knot.lchild is None:
knot.lchild = Binary_Search_Tree.__BST_Node(value, knot.height + 1)
result = knot.lchild
else:
result = self._insert(knot.lchild, value)
else: # knot.value < value
if knot.rchild is None:
knot.rchild = Binary_Search_Tree.__BST_Node(value, knot.height + 1)
result = knot.rchild
else:
result = self._insert(knot.rchild, value)
self.__height = max(self.__height, result.height)
return result
def _remove(self, knot, value):
"""delete the knot with the given value
based on: https://stackoverflow.com/a/33449471/8200213
"""
if knot.value == value: # found the node we need to delete
successor = None
if knot.rchild and knot.lchild:
# get the successor node and its parent
successor, parent = knot.rchild, knot
while successor.lchild:
successor, parent = successor.lchild, successor
# splice out successor (the parent must do this)
if parent.lchild == successor:
parent.lchild = successor.rchild
else:
parent.rchild = successor.rchild
# reset the left and right children of the successor
successor.lchild = knot.lchild
successor.rchild = knot.rchild
self._update_heights(successor, knot.height)
return successor
# else (not knot.rchild or/and not knot.lchild)
if knot.lchild: # promote the left subtree
self._update_heights(knot.lchild, knot.height)
return knot.lchild
elif knot.rchild: # promote the right subtree
self._update_heights(knot.rchild, knot.height)
return knot.rchild
# else: no children
self._update_heights(knot, knot.height)
return
# else: keep traversing
if knot.value > value and knot.lchild is not None:
# value should be in the left subtree
knot.lchild = self._remove(knot.lchild, value)
elif knot.value < value and knot.rchild is not None:
# value should be in the right subtree
knot.rchild = self._remove(knot.rchild, value)
# else: the value is not in the tree
return knot
def _update_heights(self, knot, height, maxheight=0):
# print 'update from knot value', knot.value, 'with height', knot.height, 'to height', height
maxheight = max(maxheight, knot.height)
knot.height = height
if knot.lchild is not None:
self._update_heights(knot.lchild, knot.height + 1, maxheight)
if knot.rchild is not None:
self._update_heights(knot.rchild, knot.height + 1, maxheight)
if maxheight == self.__height:
# the max height of the whole tree might have changed; re-compute
self.__height = -1
def _recompute_height(self, knot):
if not knot:
return
self.__height = max(self.__height, knot.height)
if knot.lchild is not None:
self._recompute_height(knot.lchild)
if knot.rchild is not None:
self._recompute_height(knot.rchild)
def _get_ordered(self, knot, pre=False, nodelist=None):
nodelist = nodelist or []
if knot is None:
return nodelist
if not pre:
nodelist = self._get_ordered(knot.lchild, pre, nodelist)
nodelist.append(knot.value)
if pre:
nodelist = self._get_ordered(knot.lchild, pre, nodelist)
nodelist = self._get_ordered(knot.rchild, pre, nodelist)
return nodelist
def insert_element(self, value):
self._insert(self.__root, value)
# print self.__height
def remove_element(self, value):
self.__root = self._remove(self.__root, value)
# print self.get_height()
def get_pre_order(self):
return self._get_ordered(self.__root, True)
def get_in_order(self):
return self._get_ordered(self.__root)
def get_height(self):
if self.__height == -1:
# self.__height was marked "dirty"
# re-computing tree height, as it might have changed
self._recompute_height(self.__root)
return self.__height
def __str__(self):
return ', '.join(['%d' % val for val in self.get_in_order()])
正如link发布的PidgeyUsedGust中所建议的那样,您可能希望将高度存储在节点中,这样您就可以轻松计算任何新插入节点的高度和整个高度。树。
删除节点后保持高度最新并不是一件容易的事。我提出的是一个半天真的实现,旨在在代码简单性和性能之间进行适当的折衷(这意味着时间通常是可接受的但不是恒定的;如果有人知道更好的解决方案,我会非常乐意听听他们的意见。
以下是这个想法:
_update_heights
方法的作用self.__height = -1
)get_height
,如果self.__height == -1
我们通过调用{{1}知道它的高度可能已经改变并需要重新计算方法 _recompute_height
仅由_recompute_height
而非get_height
触发的原因是为了避免每次删除元素时重新计算属性,如果这样做的话。不需要(也就是说,您可能需要删除1000个元素,然后只检查一次树的新高度)。
这里有几行来测试代码(使用了_update_heights
模块:如果你还没有安装它,你需要安装它:
drawtree
以下是你应该得到的结果:
if __name__ == '__main__':
bst = Binary_Search_Tree()
values = [7, 2, 2, 5, 1, 8, 3, 6, 9, 8, 4, 11, 10, 12]
print 'insert values', values
for val in values:
bst.insert_element(val)
print 'tree successfully built\nheight: %d' % bst.get_height()
print 'ordered: %s' % (bst, )
print 'pre-ordered:', bst.get_pre_order(), '\n'
import drawtree
drawtree.draw_bst(bst.get_pre_order())
values = [4, 2, 7, 4]
for val in values:
print '\n\nremove value %d\n' % val
bst.remove_element(val)
drawtree.draw_bst(bst.get_pre_order())
print '\n\nnew height: %d' % bst.get_height()