• 发散二叉搜索树


    根插入方法中,我们通过旋转把插入节点带到树根位置。这里,我们考虑如何使得旋转操作使树达到平衡。我们不考虑递归地使用把新近插入节点带到树顶部的单一旋转操作,而考虑把节点从作为树根的孙子(根的两代,也就是与根相距两层)之一的一个位置带到树顶部的两个旋转操作。首先,我们执行一次旋转,使节点成为树根的一个孩子。然后,执行另一次旋转,使它成为树根。根据从根到正被插入的节点的两个链接是否以相同的方式定向,存在两种本质不同的情况。当从根到正被插入的节点的两个链接以相同方式定向(例如:节点到根需要经过两个左链接,或者节点到根需要经过两个右链接)时,我们可以直接在树根执行两次相同的旋转操作,将相应节点移动到树根位置。当从根到正被插入的节点的两个链接以不同方式定向(例如:节点到根需要经过一个左链接和一个右链接,或者节点到根需要经过一个右链接和一个左链接)时,我们可以使用标准根插入方法。通过以上方式建立的二叉搜索树就是发散二叉搜索树。发散插入和标准根插入之间的区别也许显得不太合理,但它非常重要:发散操作消除了最坏情况下的二次水平性能,而这正是标准二叉搜索树的主要缺陷。

    发散插入和之前根插入算法的不同之处仅在于一个实质细节:如果搜索路径的方向是“左-左”或“右-右”,则该节点可用一次双重旋转从树的顶部而不是树的底部带到树根。

    对于源自树根的搜索路径,本程序检查其中的两个步骤的四种可能性,并执行适当的旋转操作:

    左-左:在树根右旋转两次;

    左-右:在左孩子左旋转,然后在树根右旋转;

    右-右:在树根左旋转两次;

    右-左:在右孩子右旋转,然后在树根左旋转。

     1 private:
     2     void splay(link& h, Item x)
     3     { if (h == 0)
     4        { h == new node(x, 0, 0, 1); return;}
     5        if (x.key() < h->item.key())
     6        { link& hl = h->l; int N = h->N;
     7           if (hl == 0)
     8           { h == new node(x, 0, h, N+1); return;}
     9           if (x.key() < hl->item.key())
    10           { splay(hl->l, x); rotR(h);}
    11           else { splay(hl->r, x); rotL(hl);}
    12           rotR(h);
    13        }
    14        else
    15        { link &hr = h->r; int N = h->N;
    16           if (hr == 0)
    17           { h = new node(x, h, 0, N+1); return;}
    18           if (hr->item.key() < x.key())
    19           {splay(hr->r, x); rotL(h);}
    20           else { splay(hr->l, x); rotR(hr);}
    21           rotL(h);
    22         }
    23      }
    24 public:       
    25     void insert(Item item)
    26     {splay(head, item);}
  • 相关阅读:
    small case change m and n
    关于闭包
    如何让IE兼容css3属性?
    全屏滚动插件
    bind()&call()&apply()的区别?
    nodejs和npm的关系
    数据库面试题整理
    微机原理复习整理
    软件工程复习整理
    leetcode字符串系列
  • 原文地址:https://www.cnblogs.com/ningjing213/p/12881914.html
Copyright © 2020-2023  润新知