好的,我遇到了这个看起来很简单的树问题,但开始让我疯了。
给出的树是LIKE二元搜索树,但有一点不同:
这不是一个自平衡的树;除了在新叶节点中添加新值之外,不会在插入上更改现有树结构。不允许切换或移动值或节点。
还给出了插入测试值后树结构的示例:
If we insert 8, 5, 9, 3, 3, 2, 12, 4, 10:
8
8
5
8
5 9
8
5 9
3
8
5 9
3
3
8
5 9
3
2 3
8
5 9
3 12
2 3
8
5 9
3 12
2 3
4
8
5 9
3 10 12
2 3
4
我认为10是5的正确子,因为给定的约束阻止它成为9的左子。
我的要求,给定节点的上述规则以及给定输入的预期树结构和行为的示例:为此树编写遍历和插入算法。
由于这不是一个真正的BST,我们不允许改变树,我想不出任何聪明的方法来执行遍历,除了使用另一个数据结构来按顺序完成。
我有一个可能有效的插入算法,但是因为它必须允许备份到父节点并探索其他路径(在它开始向左或向右行进的两种情况下)这将是一个非常时髦的算法。
这个问题与正常的基本编程问题并列,所以它似乎有些不合适。所以......这里有什么见解?还是我忽略了一些明显的东西?
编辑:问题已解决。它是测试提供者引入的错字。这本来是一个BST,但示例中的“10”被置于错误的位置;应该是“12”的左孩子。
答案 0 :(得分:3)
直到10出现才有意义。基本假设:这是一个错字。但它不能(也不希望)成为5岁的孩子。这是9岁的左孩子。
但它也是第一个需要重组树(以适应9到12之间)。对我来说,看起来最后的图片是中途重组。我们看到了故事的结局吗?
好的,我没有完全阅读规则2。看起来10应该成为12的左子。插入在根处采用左分支是没有充分理由的。
如果10是5或9的子节点,则它将停止为BST或除了无序二叉树之外的任何其他内容。
答案 1 :(得分:1)
第二个想法,我更倾向于相信你的例子中有一个拼写错误,而不是一个BST。 10
的位置没有意义。直到那时它才是完全有效的BST。如果将10作为12
节点的左叶插入,则将保留BST-ness。
如果leftNode.value < value <= rightNode.value
仅适用于直接子女而不适用于所有后代,那么这是一种无用的数据结构。我的意思是我猜它是可用的,但是因为你最终会在插入和查找上遍历整个树,所以它似乎毫无意义。
我想你的插入算法的大纲将类似于下面的伪Python。它的要点是尝试在可能的情况下将节点添加为叶子,或将其插入任一子树。左或右,没关系。
基本上我们只是向下看整个树,以便可以将新值添加为叶节点。如您所说,订购标准仅适用于直接儿童。你必须挑剔添加新的叶子节点。但是你会不分青红皂白地尝试左右子树。
class TreeNode:
def insert(self, value):
# Can we add it as the left leaf of this node?
if self.left is None and value < self.value:
self.left = TreeNode(value)
return True
# Can we add it as the right leaf of this node?
if self.right is None and value >= self.value:
self.right = TreeNode(value)
return True
# Can we add it somewhere down the left sub-tree?
if self.left.insert(value):
return True
# Can we add it somewhere down the right sub-tree?
if self.right.insert(value):
return True
# Didn't find anywhere to add the node.
return False
我想它变得棘手的是,如果你必须尝试平衡子树而不是随意地在树中的任意点插入新节点。如果这是一个问题,那么你可以修改上面的算法,以便在最浅的点插入。
假设有一个insert_depth
方法返回一个节点将在处插入的深度,如果是在特定子树下插入的,或者如果无法插入则返回∞。同样,这只是伪代码:
left_depth = self.left .insert_depth(value)
right_depth = self.right.insert_depth(value)
if left_depth < right_depth:
return self.left .insert(value)
else:
return self.right.insert(value)
在实际代码中,我会写一个“如果你要插入一个节点,你会在哪里插入它?”辅助方法。在两个子树上运行该方法,比较插入点,并选择一个(即最浅的)。代码有点尴尬,但它可以避免你遍历每个子树两次。