python BST插入的问题
在下面的代码中,我想不出如何执行_inserthelp函数。其他一切似乎都很顺利。。。它目前无法按预期工作。当前函数可以添加第一个节点(根节点)和第二个节点,即root.left。在那之后它就不起作用了 任务说明: 在本练习中,将为您提供一个二进制搜索树的实现。 在练习包中找到的类python BST插入的问题,python,binary-tree,Python,Binary Tree,在下面的代码中,我想不出如何执行_inserthelp函数。其他一切似乎都很顺利。。。它目前无法按预期工作。当前函数可以添加第一个节点(根节点)和第二个节点,即root.left。在那之后它就不起作用了 任务说明: 在本练习中,将为您提供一个二进制搜索树的实现。 在练习包中找到的类BST,包含这些方法 insert和find可用于插入和查找键值 对。 这些方法使用两种递归辅助方法\u inserthelp和 \u发现有助于正常工作。 您的任务是实现这些助手方法。 此外,您应该实现方法\u vis
BST
,包含这些方法
insert
和find
可用于插入和查找键值
对。
这些方法使用两种递归辅助方法\u inserthelp
和
\u发现有助于正常工作。
您的任务是实现这些助手方法。
此外,您应该实现方法\u visit\u inorder
,该方法返回
按顺序生成树节点的迭代器。
您无需更改这3个方法之外的代码即可获得完整的
要点。
'''
代码:
类节点:
def __init__(self, key, value=None):
self.key = key
self.value = value
self.left = None
self.right = None
def height(self):
"""Return the height of this node."""
left_height = 1 + self.left.height() if self.left else 0
right_height = 1 + self.right.height() if self.right else 0
return max(left_height, right_height)
def __repr__(self):
return "<BSTNode: key={!r}, value={!r}, id={}>".format(self.key, self.value, id(self))
BST级:
def __init__(self, NodeClass=BSTNode):
self.BSTNode = NodeClass
self.root = None
self.nodes = 0
# Updated after each call to insert
self.newest_node = None
def find(self, find_key):
"""Return node with key find_key if it exists. If not, return None. """
return self._findhelp(self.root, find_key)
def insert(self, new_key, value=None):
"""Insert a new node with key new_key into this BST,
increase node count by one and return the inserted node."""
if self.find(new_key) is not None:
raise KeyError("This BST already contains key {0!r}".format(new_key))
if self.root == None:
self.root = self._inserthelp(self.root, new_key, value)
self.newest_node = self.root
else:
self.newest_node = self._inserthelp(self.newest_node, new_key,value)
self.nodes += 1
return self.newest_node
def height(self):
"""Return the height of this tree."""
return self.root.height() if self.root else -1
def __iter__(self):
"""Return an iterator of the keys of this tree in sorted order."""
for node in self._visit_inorder(self.root):
yield node.key
def __len__(self):
return self.nodes
# Implement the methods below.
def _findhelp(self, node, find_key):
"""Starting from node, search for node with key find_key and return that node.
If no node with key find_key exists, return None."""
inorderlist = self._visit_inorder(node)
for _node in inorderlist:
if _node is None or find_key == _node.key:
return _node
# End search
return None
# Implement functionality to recursively choose the next node
def _inserthelp(self, node, new_key, value):
"""Starting from node, find an empty spot for the new node and
insert it into this BST."""
if node is None:
self.newest_node = BSTNode(new_key,value)
else:
# Do level order traversal until we find
# an empty place.
tree = []
tree.append(node)
node = tree[0]
tree.pop()
while len(tree):
if (not node.left):
node.left = BSTNode(new_key,value)
self.newest_node = BSTNode(new_key,value)
break
else:
tree.append(node.left)
if (not node.right):
node.right = BSTNode(new_key,value)
self.newest_node = BSTNode(new_key,value)
break
else:
tree.append(node.right)
return self.newest_node
def _visit_inorder(self, starting_node):
def inorder(node,indorderlist):
if node is None:
return
else:
inorder(node.left, inorderlist)
indorderlist.append(node)
inorder(node.right, inorderlist)
inorderlist = []
inorder(starting_node, inorderlist)
return inorderlist
测试人员:
类Test1BSTNode(unittest.TestCase):
类Test2EmptyBST(unittest.TestCase):
类test3tenodesbst(unittest.TestCase):
类Test4BSTProperty(unittest.TestCase):
如果name='main':
unittest.main(verbosity=2)您的代码非常大,很难理解,但是我认为,您正在尝试在最后一个条目中插入新的键。但这并不总是有效的。假设你有这个,英国夏令时
5
/ \
3 7
这里,5、3和7依次插入。最后一个条目是7。所以,如果你想在这里插入4,你必须将它插入3,而不是最后一个条目7。所以用你的方法是行不通的
因此,解决方案是将其插入根中,如下所示
5
/ \
3 7
\
4
但我仍然不能100%确定这是否是代码中的问题。对我来说,这是一个需要消化的大型未注释代码
def setUp(self):
self.tree = BST()
def test1_bst_init_node_class(self):
"""BSTs are initialized with a node class. (0p)."""
self.assertIs(
self.tree.BSTNode,
BSTNode,
"When no node class is specified, the BST should use the class BSTNode as the node class."
)
def test2_empty_size(self):
"""An empty BST has a size equal to zero. (0p)"""
tree_size = len(self.tree)
self.assertEqual(
0,
tree_size,
"Calling len on a tree containing no nodes should return 0, not {}"
.format(tree_size)
)
def test3_empty_find(self):
"""Searching for a key in an empty BST returns None. (0p)"""
self.assertIsNone(
self.tree.find(1),
"Calling find in an empty BST should return None."
)
def test4_empty_insert(self):
"""Calling insert on an empty tree returns the inserted node and adds it to the tree. (0p)"""
new_key = 1
new_value = "value"
inserted_node = self.tree.insert(new_key, new_value)
self.assertIsInstance(
inserted_node,
BSTNode,
"tree.insert should return an instance of BSTNode, not {0!r}."
.format(inserted_node)
)
self.assertEqual(
inserted_node.key,
new_key,
"Calling tree.insert({0}, {1}) should return a node with the key {0}, not {2}."
.format(new_key, new_value, inserted_node.key)
)
self.assertIs(
inserted_node.value,
new_value,
"Calling tree.insert({0}, {1}) should return a node with the value {1}, not {2}."
.format(new_key, new_value, inserted_node.value)
)
tree_size = len(self.tree)
self.assertEqual(
tree_size,
1,
"Calling len on a tree containing one key should return 1, not {}"
.format(tree_size)
)
def test5_find_one(self):
"""Calling find for a node which exists should return that node. (1p)"""
node = BSTNode(2)
node.left = BSTNode(1)
node.right = BSTNode(3)
self.tree.root = node
for node in (node, node.left, node.right):
found_node = self.tree.find(node.key)
self.assertIs(
found_node,
node,
"If {0!r} exists in tree, calling tree.find({1}) should return that node, not {2!r}"
.format(node, node.key, found_node)
)
def setUp(self):
self.tree = BST()
self.keys = random.sample(range(1, 11), 10)
def test1_insert_ten_nodes(self):
"""Inserting ten nodes into a BST should increase its size by ten. (1p)"""
for key in self.keys:
inserted_node = self.tree.insert(key)
self.assertIsInstance(
inserted_node,
BSTNode,
"tree.insert should return an instance of BSTNode, not {0!r}."
.format(inserted_node)
)
self.assertEqual(
inserted_node.key,
key,
"Calling tree.insert({0}) should return a node with the key {0}, not {1}."
.format(key, inserted_node.key)
)
correct_size = len(self.keys)
returned_size = len(self.tree)
self.assertEqual(
correct_size,
returned_size,
"Calling len on a tree with {0} nodes should return {0}, not {1}"
.format(correct_size, returned_size)
)
def test2_find_ten_nodes(self):
"""All keys which have been inserted should be found by the find method. (1p)"""
for key in self.keys:
self.tree.insert(key)
for key in self.keys:
returned_node = self.tree.find(key)
self.assertIsNotNone(
returned_node,
"Calling find for an existing key {0} should return the node holding the key, not None"
.format(key)
)
self.assertEqual(
returned_node.key,
key,
"Calling find for an existing key {0} should return the node holding the key, not {1!r}."
.format(key, returned_node)
)
def setUp(self):
self.tree = BST()
def test1_smaller_values_go_left(self):
"""Adding values in sorted descending order creates internal nodes with only left children. (1p)"""
# Insert nodes with keys 10, 9, 8, ... , 1
for key in range(10, 0, -1):
self.tree.insert(key)
# Starting from the root, traverse down towards the leaf, checking
# both children of each node
node = self.tree.root
for key in range(10, 1, -1):
self.assertEqual(
key,
node.key,
"After inserting keys in range 10, 9, ... , 2, 1 and then iterating in that range, expected the keys of all the left nodes starting from the root follow this sequence, but a node {0} with the key {1} was found."
.format(node, node.key)
)
# There should not be a right child
self.assertIsNone(
node.right,
"Adding keys in order 10, 9, .. , 2, 1 should not create nodes with right children, but a node {0} with a right child {1} was found."
.format(node, node.right)
)
# There should be a left child
self.assertIsNotNone(
node.left,
"Adding keys in order 10, 9, .. , 2, 1 should only create nodes with left children, but a node {0} with no left child was found."
.format(node)
)
# Go left to next node
node = node.left
# The last node is a leaf
self.assertIsNone(
node.left,
"After adding nodes in range 10, 9, ... , 2, 1, the node with key 1 should be a leaf, but it had a left child {0}."
.format(node.left)
)
self.assertIsNone(
node.right,
"After adding nodes in range 10, 9, ... , 1, the node with key 1 should be a leaf, but it had a right child {0}."
.format(node.right)
)
def test2_larger_values_go_right(self):
"""Adding values in sorted ascending order creates internal nodes with only right children. (1p)"""
# Insert nodes with keys 1, 2, ... , 10
for key in range(1, 11):
self.tree.insert(key)
# Starting from the root, traverse down towards the leaf, checking
# both children of each node
node = self.tree.root
for key in range(1, 10):
self.assertEqual(
key,
node.key,
"After inserting keys in range 1, 2, ... , 9, 10 and then iterating in that range, expected the keys of all the right nodes starting from the root to follow this sequence, but a node {0} with the key {1} was found."
.format(node, node.key)
)
# There should not be a left child
self.assertIsNone(
node.left,
"Adding keys in order 1, 2, ... , 9, 10 should not create nodes with left children, but a node {0} with a left child {1} was found."
.format(node, node.left)
)
# There should be a right child
self.assertIsNotNone(
node.right,
"Adding keys in order 1, 2, ... , 9, 10 should only create nodes with right children, but a node {0} with no right child was found."
.format(node)
)
# Go right to the next node
node = node.right
# The last node is a leaf
self.assertIsNone(
node.left,
"After adding nodes in range 1, 2, ... , 9, 10, the node with key 10 should be a leaf, but it had a left child {0}."
.format(node.left)
)
self.assertIsNone(
node.right,
"After adding nodes in range 1, 2, ... , 9, 10, the node with key 10 should be a leaf, but it had a left child {0}."
.format(node.right)
)
def test3_inorder_traversal(self):
"""An inorder traversal visits all nodes in the tree. (1p)"""
keys = random.sample(range(100), 20)
inserted = set(self.tree.insert(key) for key in keys)
visited = set(self.tree._visit_inorder(self.tree.root))
self.assertSetEqual(
visited,
inserted,
"An inorder traversal should return all nodes which have been added to the tree.\n" +
"_visit_inorder did not visit the nodes seen above although they were inserted into the tree."
)
def test4_iter_tree_keys(self):
"""Iterating the tree yields the keys of the tree in sorted ascending order. (1p)"""
keys = random.sample(range(100), 20)
for key in keys:
self.tree.insert(key)
# Shorter form of [key for key in self.tree]
# (which is possible because the class BST implements the method __iter__)
visited = list(self.tree)
# The returned values should be in sorted ascending order
correct_order = sorted(keys)
self.assertListEqual(
visited,
correct_order,
"Calling __iter__ should return an iterator of the keys of the BST in sorted ascending order.\n" +
"Note: the traversal method should not care in what order the nodes appear, if the insert method is implemented correctly, an inorder traversal will yield the keys in sorted order."
)
def test5_height_complete_tree(self):
"""The height of a complete tree with n nodes is log_2(n+1) - 1. (1p)"""
# Add keys so they form a complete tree
keys = [50, 25, 75, 20, 30, 70, 80]
for key in keys:
self.tree.insert(key)
tree_size = len(self.tree)
added_count = len(keys)
self.assertEqual(
tree_size,
added_count,
"Adding {0} keys to an initially empty tree, calling len on the tree should return {0}, not {1}."
.format(added_count, tree_size)
)
# math.log returns float
self.assertAlmostEqual(
float(self.tree.height()),
math.log(len(keys) + 1, 2) - 1,
)
5
/ \
3 7
5
/ \
3 7
\
4