播放树插入

时间:2010-01-05 19:49:36

标签: language-agnostic binary-tree wikipedia splay-tree

通过一些练习来磨练我的二叉树技能,我决定实现一个splay树,如Wikipedia: Splay tree中所述。

我没有得到的一件事是关于插入的部分。

它说:

  

首先,我们在splay树中搜索x。如果x尚不存在,那么我们将找不到它,而是它的父节点y。其次,我们对y执行一个splay操作,它将y移动到splay树的根。第三,我们以适当的方式将新节点x作为root插入。这样,y是新根x的左或右子。

我的问题是:与文章中的其他例子相比,上述文字似乎过于简洁,为什么会这样?似乎这里遗漏了一些问题。例如,在将y节点向上扩展到根之后,我不能盲目地用x替换root,并将x作为左或右子进行处理。

让我们假设树中不存在该值。

我有这棵树:

           10
          /  \
         5    15
        / \    \
       1   6    20

我要插入8.通过上面的描述,我将找到6节点,在普通的二叉树中,8将被添加为6节点的右子节点,但是这里我首先有将6节点展开到root:

            6
           / \
          5   10
         /     \
        1       15
                 \
                  20

然后这两个中的任何一个都显然是错误的:

          8                                  8
           \                                /
            6                              6
           / \                            / \
          5   10                         5   10
         /     \                        /     \
        1       15                     1       15
                 \                              \
                  20                             20

    6 is not greater than 8          10 is not less than 8

在我看来,首先进行splaying,然后以root身份正确添加新值的唯一方法意味着我必须检查以下条件(用于将splayed节点添加为新根的左子节点) :

  1. 我展示给根的节点小于新根(6< 8)
  2. 我向根发布的节点中最右边的子节点也小于新根节点(20 8)
  3. 但是,如果我要拆分我展示的节点,通过选择正确的子节点并将其作为新节点的右子节点附加,我会得到:

                            8
                           / \
                          6   10
                         /     \
                        5       15
                       /         \
                      1           20
    

    但是,这个简单的改变是否会给我一棵正确的树?我很难想出一个例子,但这可能导致以下结果:

    • 我要添加的新值高于临时根(我显示给根的节点),还高于临时根的右子的最左边的子节点?

    IE中。一个树在展开后基本上看起来像这样,但在我更换根之前?

                            10
                           /  \
                          5    15
                              /  \
                            11    20
    

    我想添加13,这将使新树像这样:

                            13
                           /  \
                         10    15
                         /    /  \
                        5   11    20  <-- 11, on the wrong side of 13
    

    或者这种情况永远不会发生?

    我的第二个问题是:如下所示重写操作不会轻松得多:

      

    首先,我们在splay树中搜索x。如果x尚不存在,那么我们将找不到它,而是它的父节点y。 然后我们将新节点添加为父节点的左子节点。。第三,我们在我们添加的节点上执行展开操作,这将移动新值到了展开树的根。

    强调我的表现我改变了什么。

3 个答案:

答案 0 :(得分:5)

我不明白你描述的问题是怎么发生的。如果要在此树中插入13,首先必须找到它的位置:

                    10
                   /  \
                  5    15
                      /  \
                    11    20

从10开始,你从右边开始,从左边的15开始,从右边开始,然后你就没有了。如果13已经在树中,我们会发现它是11的右子。所以根据规则我们在11上执行一个splay操作,它将11移动到splay树的根:

                    11
                   /  \
                  10   15
                 /       \
                5         20

然后我们添加13作为新的根,其中11作为左子:

                    13
                   /  \
                  11   15
                 /       \
                10        20
               /
              5

现在没有问题。

  

首先,我们在splay树中搜索x。如果x尚不存在,那么我们将找不到它,而是它的父节点y。然后我们将新节点添加为父节点的左子节点或右子节点。第三,我们在添加的节点上执行splay操作,将新值移动到splay树的根。

这听起来对我来说也会起作用,但如果我是你,我只会尝试实现维基百科中描述的版本,因为很多人已经测试过,而且已经有很好的文档记录。

答案 1 :(得分:1)

“Splay Tree”立刻让我记得我刚读过CUJ的一篇文章,你可能会在那里找到一些见解:Implementing Splay Tree in C++

  

第三,我们以适当的方式将新节点x作为root插入。这样,y是新根x的左或右子。

是的,但是这个新根x必须有2个孩子,这就是为什么这句话听起来有点混乱。

答案 2 :(得分:1)

新节点将像普通二进制搜索树一样添加到树中。然后,新节点将显示为根或根来自第一级。此外,当我们插入一个新节点时,我们需要找到放置它的位置,因此我们进行查找。并且所有操作(包括在splay树上查找)都会触发splay操作。也许这就是为什么维基百科的文章就是这样描述的。我只是插入新节点并将其展开。无论哪种方式,树都变得比它更平衡。工作得很好here