数据结构实现之Splay伸展树

Splay Tree是一种二叉查找树,通过旋转操作将查找节点移动到树根,提升查找效率。其特点在于利用局部性原理,对于频繁访问的节点能提供接近O(1)的查找速度,尽管最坏情况下时间复杂度为O(logn)。本文介绍了Splay Tree的节点定义、查找、插入和删除等操作。
摘要由CSDN通过智能技术生成

Splay Tree 是二叉查找树的一种,它与平衡二叉树、红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋转到树根的位置,这样就使得SplayTree天生有着一种类似缓存的能力,因为每次被查找到的节点都会被搬到树根的位置,所以当80%的情况下我们需要查找的元素都是某个固定的节点,或者是一部分特定的节点时,那么在很多时候,查找的效率会是O(1)的效率!当然如果查找的节点是很均匀地分布在不同的地方时,Splay Tree的性能就会变得很差了,但Splay Tree的均摊时间复杂度还是O(logn)的。
摘自http://www.nocow.cn/index.php/Splay_Tree

PPT来自清华邓俊辉数据结构-BST-Splay(学堂在线有对应视频讲解)
4
5
先zig(g)再zig(p)的要比先zig(p)再zig(g)的局部性效果要好,前者会使p成为g的左子结点,从而不能很好发挥SplayTree利用局部性的目的。
6
7

Splay Tree 结点定义

//Splay结点定义
    private class Node {
        public Node left;
        public Node right;
        public Node parent;
        public Key key;
        public Value val;
        public Node(Key k,Value v) {
            key = k; val = v; parent = null; left = null; right = null;
        }
    }

splay

private Node splay(Node v) {
        if(v == null) return null;
        Node p,g;//v的父亲与祖父
        //自下而上,反复对v做双层伸展
        while((p=v.parent)!=null && (g = p.parent)!=null) {
            Node gg = g.parent;//每轮之后v都以原曾祖父(great-grand parent)为父
            if(isLChild(v)) {
                if(isLChild(p)) {
  //zig-zig,zig(g)先g结点右旋,zig(p)再p右旋
                    attachAsLChild(g, p.right);
                    attachAsRChild(p,g);
                    attachAsLChild(p, v.right);
                    attachAsRChild(v,p);
                }
                else {
  //zig-zag,zig(p)先p右旋,再g左旋zag(g)
                    attachAsLChild(p,v.right);
                    attachAsRChild(v,p);
                    attachAsRChild(g,v.left);
                    attachAsLChild(v,g);
                }
            }
            else {
                if(isRChild(p)) {
  //zag-zag,zag(g)先g结点左旋,zip(p)再p左旋
                    attachAsRChild(g,p.left);
                    attachAsLChild(p,g);
                    attachAsRChild(p,v.left);
                    attachAsLChild(v,p);
                }
                else {
  //zag-zig,先p左旋,zag(p),再g右旋zig(g)
                    attachAsRChild(p,v.left);
                    attachAsLChild(v,p);
                    attachAsLChild(g,v.right);
                    attachAsRChild(v,g);
                }
            }
            //若v原先的曾祖父gg不存在,则v现在应为树根
            if(gg==null)v.parent = null;
            else {
  //否则,gg此后应该以v作为左或右孩子
                if(gg.left == g) attachAsLChild(gg,v);
                else attachAsRChild(gg,v);
            }
        }//双层伸展结束时,必有g == NULL,但p可能非空
        //若p果真非空,则额外再做一次单旋
        if(p!=null && p == v.parent) {
            if(isLChild(v)) {
  //zig
                attachAsLChild(p,v.right);
                attachAsRChild(v,p);
            }
            else {
  //zag
                attachAsRChild(p,v.left);
          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值