树堆

在树堆中,它可以在O(log⁡ n)时间内完成查找、插入和删除。

import java.util.Random;
 
// 一个 Treap 节点
class TreapNode
{
    int data;
    int priority;
    TreapNode left, right;
 
    // 构造函数
    TreapNode(int data)
    {
        this.data = data;
        this.priority = new Random().nextInt(100);
        this.left = this.right = null;
    }
}
 
class Treap
{
    /* 左旋转给定treap的函数
 
          r                         R
         / \      左旋转      / \
        L   R        ———>         r   Y
           / \                   / \
          X   Y                 L   X
    */
    public static TreapNode rotateLeft(TreapNode root)
    {
        TreapNode R = root.right;
        TreapNode X = root.right.left;
 
        // 旋转
        R.left = root;
        root.right = X;
 
        // 设置一个新的根
        return R;
    }
 
    /* 向右旋转给定的treap的函数
 
            r                        L
           / \     向右旋转     / \
          L   R        ———>        X   r
         / \                          / \
        X   Y                        Y   R
    */
    public static TreapNode rotateRight(TreapNode root)
    {
        TreapNode L = root.left;
        TreapNode Y = root.left.right;
 
        // 旋转
        L.right = root;
        root.left = Y;
 
        // 设置一个新的根
        return L;
    }
 
    // 将具有优先级的给定键插入到treap中的递归的函数
    public static TreapNode insertNode(TreapNode root, int data)
    {
        // 基本情况
        if (root == null) {
            return new TreapNode(data);
        }
 
        // 如果数据小于根节点,则插入左子树;
        // 否则,插入右子树
        if (data < root.data)
        {
            root.left = insertNode(root.left, data);
 
            // 如果堆属性被破坏,则向右旋转
            if (root.left != null && root.left.priority > root.priority) {
                root = rotateRight(root);
            }
        }
        else {
            root.right = insertNode(root.right, data);
 
            // 如果违反了堆属性,则向左旋转
            if (root.right != null && root.right.priority > root.priority) {
                root = rotateLeft(root);
            }
        }
 
        return root;
    }
 
    // 递归的函数在给定的treap中搜索一个键
    public static boolean searchNode(TreapNode root, int key)
    {
        // 如果键不存在于树中
        if (root == null) {
            return false;
        }
 
        // 如果找到密钥
        if (root.data == key) {
            return true;
        }
 
        // 如果key小于根节点,则在左子树中搜索
        if (key < root.data) {
            return searchNode(root.left, key);
        }
 
        // 否则,在右子树中搜索
        return searchNode(root.right, key);
    }
 
    // 从给定的treap中删除一个键的递归的函数
    public static TreapNode deleteNode(TreapNode root, int key)
    {
        // 基本情况:在树中找不到键
        if (root == null) {
            return null;
        }
 
        // 如果key小于根节点,则递归左子树
        if (key < root.data) {
            root.left = deleteNode(root.left, key);
        }
 
        // 如果key大于根节点,则递归到右子树
        else if (key > root.data) {
            root.right = deleteNode(root.right, key);
        }
 
        // 如果找到密钥
        else {
            // 案例一:要删除的节点没有子节点(是叶子节点)
            if (root.left == null && root.right == null)
            {
                // 释放内存并将root更新为null
                root = null;
            }
 
            // 情况2:要删除的节点有两个孩子
            else if (root.left != null && root.right != null)
            {
                // 如果左孩子的优先级低于右孩子
                if (root.left.priority < root.right.priority)
                {
                    // 在根上调用 `rotateLeft()`
                    root = rotateLeft(root);
 
                    //递 归删除左孩子
                    root.left = deleteNode(root.left, key);
                }
                else {
                    // 在根上调用 `rotateRight()`
                    root = rotateRight(root);
 
                    // 递 归删除右孩子
                    root.right = deleteNode(root.right, key);
                }
            }
 
            // 案例3:要删除的节点只有一个孩子
            else {
                // 选择一个子节点
                TreapNode child = (root.left != null)? root.left: root.right;
                root = child;
            }
        }
 
        return root;
    }
 
    // 实用函数来打印一个treap的二维视图
    // 反向中序遍历
    public static void printTreap(TreapNode root, int space)
    {
        final int height = 10;
 
        // 基本情况
        if (root == null) {
            return;
        }
 
        // 增加关卡之间的距离
        space += height;
 
        // 先打印右孩子
        printTreap(root.right, space);
        System.lineSeparator();
 
        // 用空格填充后打印当前节点
        for (int i = height; i < space; i++) {
            System.out.print(' ');
        }
 
        System.out.println(root.data + "(" + root.priority + ")");
 
        //打印左孩子
        System.lineSeparator();
        printTreap(root.left, space);
    }
 
    public static void main(String[] args)
    {
        // Treap 键
        int[] keys = { 5, 2, 1, 4, 9, 8, 10 };
 
        // 构造一个Treap
        TreapNode root = null;
        for (int key: keys) {
            root = insertNode(root, key);
        }
 
        System.out.println("Constructed treap:\n");
        printTreap(root, 0);
 
        System.out.println("\nDeleting node 1:\n");
        root = deleteNode(root, 1);
        printTreap(root, 0);
 
        System.out.println("\nDeleting node 5:\n");
        root = deleteNode(root, 5);
        printTreap(root, 0);
 
        System.out.println("\nDeleting node 9:\n");
        root = deleteNode(root, 9);
        printTreap(root, 0);
    }
}

Last updated