伸展树Java实现

特性

伸展树(Splay Tree)是特殊的二叉查找树,当某个节点被访问时,伸展树会通过旋转使该节点成为树根。

树结点和构造函数

public class SplayTree<T extends Comparable<T>> {

    private class SplayTreeNode<T extends Comparable<T>> {
        public T key;
        public SplayTreeNode<T> left;
        public SplayTreeNode<T> right;

        public SplayTreeNode() {
            this.left = null;
            this.right = null;
        }

        public SplayTreeNode(T key, SplayTreeNode<T> left, SplayTreeNode<T> right) {
            this.key = key;
            this.left = left;
            this.right = right;
        }
    }
	// 根结点
    private SplayTreeNode<T> mRoot; 
}
复制代码

旋转

  1. 首选做一个循环,直到tree.left或者tree.right==null为止
  2. 当需要访问的key比每次循环的根结点的值小的时候,就需要右旋转;比根结点大的时候就需要左旋转。
  3. 左旋和右旋的方式和AVL树种LL和RR的方式一样,只是最后多一个赋值成新tree的操作。
  4. 链接的过程,如果是右旋的话(LL方式旋转)则设置一个N的空结点,让原来这颗树作为N的左孩子;如果是左旋的话(RR方式旋转)则设置一个N的空结点,让原来这棵树成为N的右孩子
 private SplayTreeNode<T> splay(SplayTreeNode<T> tree, T key) {
        if (tree == null)
            return tree;

        SplayTreeNode<T> N = new SplayTreeNode<>();
        SplayTreeNode<T> l = N;
        SplayTreeNode<T> r = N;
        SplayTreeNode<T> c;
        for (; ; ) {
            int cmp = key.compareTo(tree.key);
            if (cmp < 0) {
                //在左子树上
                if (tree.left == null)
                    break;
                if (key.compareTo(tree.left.key) < 0) {
                    c = tree.left;
                    tree.left = c.right;
                    c.right = tree;
                    tree = c;
                    if (tree.left == null)
                        break;
                }
                //这里是link right
                r.left = tree;
                r = tree;
                tree = tree.left;
            } else if (cmp > 0) {
                if (tree.right == null)
                    break;
                if (key.compareTo(tree.right.key) > 0) {
                    //这里是一个类似AVL树RR旋转的过程
                    c = tree.right;
                    tree.right = c.left;
                    c.left = tree;
                    //这里就完成了一次旋转,形成新的tree
                    tree = c;
                    //判断tree是否有右结点,没有的话就旋转结束了
                    if (tree.right == null)
                        break;
                }

                //这里是一个link left的过程,在最上的结点上新增一个空结点,让这个空结点成为tree,
                l.right = tree;
                l = tree;
                tree = tree.right;
            } else
                break;
        }
        //这里是组合的过程,这里不懂
        l.right = tree.left;
        r.left = tree.right;
        tree.left = N.right;
        tree.right = N.left;
        return tree;
    }
复制代码

插入结点

 private SplayTreeNode<T> insert(SplayTreeNode<T> tree, SplayTreeNode<T> z) {
        int cmp;
        SplayTreeNode<T> y = null;
        SplayTreeNode<T> x = tree;
        while (x != null) {
            y = x;
            cmp = z.key.compareTo(x.key);
            if (cmp < 0) {
                //在左子树上;
                x = x.left;
            } else if (cmp > 0) {
                //在右子树上
                x = x.right;
            } else {
                z = null;
                return tree;
            }
        }

        if (y== null)
            tree = z;
        else {
            cmp = z.key.compareTo(y.key);
            if (cmp < 0)
                y.left = z;
            else
                y.right = z;
        }

        return tree;

    }
复制代码

删除结点


 /*
     * 删除结点(z),并返回被删除的结点
     *
     * 参数说明:
     *     bst 伸展树
     *     z 删除的结点
     */
    private SplayTreeNode<T> remove(SplayTreeNode<T> tree, T key) {
        SplayTreeNode<T> x;

        if (tree == null)
            return null;

        // 查找键值为key的节点,找不到的话直接返回。
        if (search(tree, key) == null)
            return tree;

        // 将key对应的节点旋转为根节点。
        tree = splay(tree, key);

        if (tree.left != null) {
            // 将"tree的前驱节点"旋转为根节点
            x = splay(tree.left, key);
            // 移除tree节点
            x.right = tree.right;
        } else
            x = tree.right;

        tree = null;

        return x;
    }

    public void remove(T key) {
        mRoot = remove(mRoot, key);
    }
复制代码

Reference

伸展树 自底向上 自顶向下 Java数据结构与算法解析(八)——伸展树

转载于:https://juejin.im/post/5a37282ff265da4315240000

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值