java实现Treap

Treap树(笛卡尔树)= Heap (堆)+BST (二叉搜索树 binary search trea)。这是一颗既满足堆的性质与BST的性质的树。

当我们只知道一颗二叉查找树(BST)的 valval 的时候,我们可以将任意一个点作为根节点,任意一个比此点 valval 小的点作为左儿子,任意一个比此点 valval 大的点作为右儿子,按照此种方法建树后,如果我们进行中序遍历,会发现遍历出的序列是有序且一定的。

那么小顶堆(Heap)的性质是修正值最小的点一定在最上方,也就是根,左儿子和右儿子的 rndrnd 是左子树和右子树分别的最小值,由于有BST的性质限制,又有了Heap的性质限制后我们就发现这棵树的结构也是一定的。

public class Treap{
    class Node{
        Node right;
        Node left;
        Object data;
        Node parent;
        int priority;
        public Node(Object d,int pro,Node p){
            data=d;priority=pro;parent=p;
        }
        public void printTree(Node root){
            if(root!=null){
                printTree(root.left);
                System.out.println(root.data);
                printTree(root.right);
            }
        }

        /**
         *查找
         */
        public Node query(Node root,int value){
            Node node=root;
            while(node!=null){
                if((int)node.data>value){
                    node=node.left;
                }else if((int)node.data<value){
                    node=node.right;
                }else{
                    return node;
                }
            }
            return null;
        }
        public Node insert(Object value,Node root,Node p){
            if(root==null)
                return new Node(value,(int)(Math.random()*100),p);
            if(root.data.hashCode()>value.hashCode()){
                root.left=insert(value,root.left,root);
                //插入完成后,根据优先级进行旋转操作
                //左子节点的优先级值小于根节点的优先级
                //根据小顶堆的规则,需要进行右旋操作
                if(root.left.priority< root.priority){
                   root=rightRotate(root);
                }
            }else if(root.data.hashCode()<value.hashCode()){
                root.right=insert(value,root.right,root);
                if(root.right.priority<root.priority){
                    root=leftRotated(root);
                }
            }else{

            }
            return root;
        }
/**
 * 进行删除操作
 * 如果是叶子节点 则直接删除,不是叶子节点,就进行旋转,直至该节点是叶子节点,然后删除
 */
    public Node delete(Object value,Node root){
        if(root!=null){
            if(root.data.hashCode()>value.hashCode()){
                root.left=delete(value,root.left);
            }
        }else if(root.data.hashCode()<value.hashCode()){
            root.right=delete(value,root.right);
        }else{
            //root 已经成为该目标节点
            if(root.left==null && root.right==null){
                return null;
            }
            else if(root.left!=null &&root.right!=null){
                if(root.left.priority<root.right.priority){
                    root=rightRotate(root);
                    root.right=delete(value,root.right);
                }else{
                    root=leftRotated(root);
                    root.left=delete(value,root.left);
                }
            }else if(root.right==null){
                  root=rightRotate(root);
                root.right=delete(value,root.right);
            }else if(root.left==null){
                root=leftRotated(root);
                root.left=delete(value,root.left);
            }

        }
        return root;
    }
    //左子节点右旋
    public Node rightRotate(Node treeNode) {
        // temp为左子结点
        Node temp = treeNode.left;
        //将父结点的左边指向 temp的右子结点
        treeNode.left = temp.right;
        // 将temp结点的右边指向父结点
        temp.right = treeNode;
        // 进行上面两步操作,在纸上画一下就找到其右旋成功了,
        // 即左子结点变为根结点了

        // 返回此时旋转后的真正根结点
        return temp;
    }
    //右子节点左旋
    public Node leftRotated(Node node){
        
       Node tem=node.right;
        
        node.right=tem.left;
       
        tem.left=node;
        return tem;
    }
    }
    Node root;
    public void insert(Object value){
        if(root==null)
            root=new Node(value,(int)(Math.random()*100),null);
        else root.insert(value,root,null);
    }
    public void print(){
        root.printTree(root);
    }
    public void rotated(){
        root.leftRotated(root);
    }
}