遍历并插入奇怪的二叉树

时间:2010-09-20 22:17:36

标签: algorithm binary-tree traversal

好的,我遇到了这个看起来很简单的树问题,但开始让我疯了。

给出的树是LIKE二元搜索树,但有一点不同:

  1. 对于Node,leftNode.value<值< = rightNode.value。但是,(通过省略任何进一步的信息,以及下面的例子),这仅适用于直接的孩子,而不是每个孩子下面的节点。因此,左子树中某处的值可能是> =当前节点的值。
  2. 这不是一个自平衡的树;除了在新叶节点中添加新值之外,不会在插入上更改现有树结构。不允许切换或移动值或节点。

    还给出了插入测试值后树结构的示例:

    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”的左孩子。

2 个答案:

答案 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)

在实际代码中,我会写一个“如果你要插入一个节点,你会在哪里插入它?”辅助方法。在两个子树上运行该方法,比较插入点,并选择一个(即最浅的)。代码有点尴尬,但它可以避免你遍历每个子树两次。