Treap树堆

news2024/11/20 20:42:44

1.概念

当串行一直插入连续的数字,会导致树成为一个链表,时间复杂度变为0N
在这里插入图片描述
树堆概念:
主要体现的思想是随机插入数字,会给每个数字赋予一个优先级——>目的是让插入的关键字满足二叉树(节点的性质满足=(关键字:优先级))

在这里插入图片描述
树堆=二叉搜索树+堆
1.首先按照关键字插入,1插入,然后插入关键字2并记录优先级,2<1理当2在1的右边

2.后面发现关键字2的优先级<1的优先级,所以2需要上浮满足小顶堆**(左旋上浮)**

特点:被旋转的节点的左子树会到原父节点的右子树上(节点左旋,那么节点的右子树还是一直挂着保护着的)
在这里插入图片描述
左旋右旋
在这里插入图片描述
有点像生活现象:
新来的员工比老员工工作积极亢奋,就会往上冲去比较优先级,而老的就大多就安于现状所以不会网上冲了
在这里插入图片描述
如果插入顺序是随机的,则一颗二叉搜索树的深度是解决0(logn)的
我们可以按照优先级进行排序,然后再按照树那样进行插入(按照树堆的方式进行插入)

时间复杂度(深度-0(h)插入+0(h)左旋):h-0(log2n);
如何左旋:选择一个较小优先级的叶子节点,然后与父节点进行交换即可

如何插入

  1. 按照二叉查找树的插入方式,将节点插入到树叶中
  2. 再按照priority项的堆序(小顶堆)性质进行节点位置的调整

如何删除
将要删除的节点与最后一个节点交换,然后删除最后叶子节点即可,最后将树下沉保证堆的性质

  1. 找到相应的结点
  2. 若该结点为叶子结点,则直接删除;
    若该结点为非叶子节点,则进行相应的旋转,直到该结点为叶子节点,然后进行删除。

优缺点

  • Treap简明易懂。Treap只有两种调整方式,左旋和右旋。
  • Treap易于编写。Treap只需维护一个满足堆序的修正值,修正值一经生成无需修改。
  • Treap稳定性佳。Treap的平衡性虽不如 AVL,红黑树, SBT等平衡树,但是 Treap也不会退化,可以保证期望 O(logN)的深度。Treap的稳定性取决于随机数发生器。
  • Treap具有良好的实践效果。各种实际应用中, Treap的稳定性表现得相当出色,没有因为任何的构造出的数据而退化。
  • Treap像跳跃表一样使用了随机数,使Treap树的深度为O(logN),所以对于任意的输入其操作的时间复杂度都为O(logN)
  • 查找操作的时间等同于非平衡二叉查找树,所以比平衡二叉查找树要慢
  • 插入操作的时间只比递归非平衡二叉查找树稍慢。
  • 删除操作的时间虽然也要慢的多,但也是O(logN)。

差异
相当于普通BST的进化版,在此基础上加了堆的性质保证平衡(满足大根堆或者小根堆)

2.代码实现

package chapter12;

import chapter04.MyCustomException;

import java.util.Random;

public class Treap<T extends Comparable<? super T>> {
    private Node<T> root;  // 根节点
    private final Node<T> nullNode;  // 空节点

    private static class Node<T> {
        static Random random = new Random();  // 随机数发生器
        T element;  // key值
        int priority;  // 优先级
        Node<T> left;
        Node<T> right;

        Node(T element) {
            this(element, null, null);
        }

        Node(T element, Node<T> left, Node<T> right) {
            this.element = element;
            this.priority = random.nextInt();
            this.left = left;
            this.right = right;
        }
    }

    // ************************************************************************************************************
    public Treap() {
        nullNode = new Node<>(null);
        nullNode.left = nullNode.right = nullNode;
        nullNode.priority = Integer.MAX_VALUE;
        root = nullNode;
    }

    public void makeEmpty() {
        root = nullNode;
    }

    public boolean isEmpty() {
        return root == nullNode;
    }

    public void insert(T element) {
        root = insert(element, root);
    }

    public void remove(T element) {
        root = remove(element, root);
    }

    public boolean contains(T element) {
        Node<T> current = root;
        nullNode.element = element;
        while (true) {
            int compareResult = element.compareTo(current.element);
            if (compareResult < 0)
                current = current.left;
            else if (compareResult > 0)
                current = current.right;
            else
                return current != nullNode;
        }
    }

    public T findMin() {
        if (isEmpty()) {
            throw new MyCustomException();
        }
        return findMin(root).element;
    }

    public T findMax() {
        if (isEmpty()) {
            throw new MyCustomException();
        }
        return findMax(root).element;
    }

    public void printTree() {
        printTree(root);
    }

    // ************************************************************************************************************

    /**
     * treap的插入操作:
     * 1.按照二叉查找树的插入方式,将节点插入到树叶中
     * 2.再按照priority项的堆序(小顶堆)性质进行节点位置的调整
     *
     * @param element:要插入的元素
     * @param node:本节点
     */
    private Node<T> insert(T element, Node<T> node) {
        if (node == nullNode) {
            return new Node<>(element, nullNode, nullNode);  // 插入到叶子节点中
        }
        int compareResult = element.compareTo(node.element);
        if (compareResult < 0) {
            node.left = insert(element, node.left);  // 按二叉查找树的性质插入
            if (node.left.priority < node.priority) {  // 按priority的堆序性质(小顶堆)进行调整
                node = rotateWithLeftChild(node);
            }
        } else if (compareResult > 0) {
            node.right = insert(element, node.right);
            if (node.right.priority < node.priority) {
                node = rotateWithRightChild(node);
            }
        }
        return node;
    }

    // 左一字型的单旋转
    private Node<T> rotateWithLeftChild(Node<T> t) {
        Node<T> tmp = t.left;
        t.left = tmp.right;
        tmp.right = t;
        return tmp;
    }

    // 右一字型的单旋转
    private Node<T> rotateWithRightChild(Node<T> t) {
        Node<T> tmp = t.right;
        t.right = tmp.left;
        tmp.left = t;
        return tmp;
    }

    /**
     * treap的删除操作:
     * 1.找到相应的结点
     * 2.若该结点为叶子结点,则直接删除;
     * 若该结点为非叶子节点,则进行相应的旋转,直到该结点为叶子节点,然后进行删除。
     *
     * @param element:要删除的元素
     * @param node:本节点
     */
    private Node<T> remove(T element, Node<T> node) {
        if (node != nullNode) {
            int compareResult = element.compareTo(node.element);
            if (compareResult < 0) {
                node.left = remove(element, node.left);
            } else if (compareResult > 0) {
                node.right = remove(element, node.right);
            } else {  // compareResult = 0,即找到对应项
                if (node.left.priority < node.right.priority) {
                    node = rotateWithLeftChild(node);
                } else {
                    node = rotateWithRightChild(node);
                }
                if (node != nullNode) {  // 如果node不是nullNode,则说明未旋转之前的node不为树叶,需要将之前的node往树叶处旋转,然后在进行删除
                    node = remove(element, node);
                } else {
                    node.left = nullNode;  // 如果node是nullNode,则说明未旋转之前的node为树叶,可以直接删除。
                }
            }
        }
        return node;
    }

    private Node<T> findMin(Node<T> node) {
        if (node.left == nullNode) {
            return node;
        } else {
            return findMin(node.left);
        }
    }

    private Node<T> findMax(Node<T> node) {
        if (node.right == nullNode) {
            return node;
        } else {
            return findMin(node.right);
        }
    }

    private void printTree(Node<T> node) {
        if (node != nullNode) {
            printTree(node.left);
            System.out.println(node.element);
            printTree(node.right);
        }
    }

    // ************************************************************************************************************
    public static void main(String[] args) {
        Treap<String> treap = new Treap<>();
        treap.insert("GG");
        treap.insert("TT");
        treap.insert("OO");
        treap.insert("BB");
        treap.insert("NN");
        treap.insert("LL");
        treap.insert("GG");
        treap.insert("UU");
        treap.printTree();
        treap.remove("GG");
        treap.remove("TT");
        treap.remove("OO");
        treap.remove("BB");
        treap.remove("NN");
        treap.remove("LL");
        treap.remove("UU");
        treap.printTree();
        treap.insert("AA");
        System.out.println();
        System.out.println(treap.root.element);
    }
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/110373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

155. SAP Smart Table 的 Personalization(个性化配置)

本教程的前一步骤,我们介绍了 SAP Smart Table 和 Smart Filter Bar 配合起来的使用方法: SAP UI5 应用开发教程之一百五十四 - SAP UI5 Smart Table 和 Smart Filter Bar 的联合使用方法介绍本文我们在此基础上更进一步,为 Smart Table 增添一个 Personalization(个性化配置…

蓝桥杯备赛Day2——知识拾遗

目录 字符串 格式化输出 字符串的常用方法 1、去掉空格和特殊符号 2、字符串的测试和替换函数 3、字符串的分割 4、连接字符串 5.截取字符串(切片&#xff09; ​编辑 6、eval函数 7、关键字in&#xff08;返回布尔值&#xff09; 8、startswith()、endswith() 9、…

第5章 管理端(Vue)布局面的重构与路由的全局存储

1 重构路由&#xff1a;src\router\index.js import { createRouter, createWebHashHistory } from vue-router import HomeView from ../views/HomeView.vue //注意&#xff1a;path属性所对应的字符串不能与“*.vue”文件名相同否则会出现错误。 const routes [{ path: …

https搭建-基于phpstudy+openssl实现https网站搭建

目录 一、前言 1.https简介 2.生成ssl证书 二、下载安装phpstudy 1.下载phpstudy 2.启动phpstudy 三、利用openssl证书搭建https 1.进行phpstudy的配置https 2.把CA自签名证书导入受信任的根证书中 3.更改主机host文件 一、前言 1.https简介 HTTPS &#xff0c;是以…

扫雷游戏的设计——大型程序的设计思路

目录 &#x1f33a;了解扫雷游戏的作用原理并梳理思路 &#x1f33a;扫雷游戏前期部分完善 &#x1f337;文件的创建 &#x1f337;创建菜单&#xff0c;完善主函数 &#x1f333;代码呈现&#xff1a; &#x1f33a;扫雷游戏主题内容 &#x1f335;第一步初始化棋盘 &#x1…

CSDN博客运营团队2022年H2总结

前言 在2022年的年中&#xff0c;我们对外公布了我们的年中盘点&#xff1a;2022年上半年部分团队的总结 我们希望尽可能的公开我们的工作内容&#xff0c;让更多人可以了解CSDN的变化&#xff0c;同时也希望收到大家的真实反馈&#xff1a;你期待的新功能上线了吗&#xff1…

创建react项目

1.安装Node.js:官网Node.js下载 2.检查安装 3.命令安装&#xff1a;cnpm:npm install -g cnpm --registryhttps://registry.npm.taobao.org(cnpm比较快) 4.查cnpm安装是否成功&#xff1a;命令&#xff1a;cnpm -v 5.react脚手架安装命令&#xff1a;cnpm i -g create-react…

深度!用“极速统一”,开启金融行业数据分析新范式

作者&#xff1a;51CTO 赵立京 数据库作为金融信息系统的核心基础设施&#xff0c;历经数十年发展&#xff0c;为金融行业转型升级提供了有力的技术支撑。同时&#xff0c; 以银行为代表的金融行业是数据库销售额占比最高的市场&#xff0c;也是对数据库技术依赖度最高、要求最…

写出更现代化的Python代码:聊聊 Type Hint

Type Hint是 Python 3.5 新增的支持&#xff0c;中文可以译为 类型提示。屏幕前的你或许听过&#xff0c;又或许没有。所以今天&#xff0c;让我们一起了解了解。本文基于 Python 3.10.4&#xff0c;部分代码需要在 Python 3.10.0 及以上运行&#xff0c;原因在后续文章中会有说…

kali系统渗透window实现屏幕监控

1安装 VMware15.5,kali系统&#xff0c;桥接模式 链接&#xff1a;https://pan.baidu.com/s/1Y3ftPnzCj0NaMQNDAhIUjw 提取码&#xff1a;3k2w 2修改sshd_config vim /etc/ssh/sshd_config 去掉这两行注释 完成后保存 esc : wq! 重启SSH服务 /etc/init.d/ssh restart Fina…

一文看懂Linux内核页缓存(Page Cache)

我们知道文件一般存放在硬盘&#xff08;机械硬盘或固态硬盘&#xff09;中&#xff0c;CPU 并不能直接访问硬盘中的数据&#xff0c;而是需要先将硬盘中的数据读入到内存中&#xff0c;然后才能被 CPU 访问。 由于读写硬盘的速度比读写内存要慢很多&#xff08;DDR4 内存读写…

C语言期末集训3(大一,超基础,小猫猫大课堂配套练习)——循环结构

更新不易&#xff0c;麻烦多多点赞&#xff0c;欢迎你的提问&#xff0c;感谢你的转发&#xff0c; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我…

[第十二届蓝桥杯/java/算法]F——时间显示

&#x1f9d1;‍&#x1f393;个人介绍&#xff1a;大二软件生&#xff0c;现学JAVA、Linux、MySQL、算法 &#x1f4bb;博客主页&#xff1a;渡过晚枫渡过晚枫 &#x1f453;系列专栏&#xff1a;[编程神域 C语言]&#xff0c;[java/初学者]&#xff0c;[蓝桥杯] &#x1f4d…

五步法搞定BI业务需求梳理

五步法搞定BI业务需求梳理。高手就是把复杂的事情简单化&#xff0c;简单的东西重复做、认真做。 五步法是哪五步 第一&#xff0c; 明确用户。商业智能BI项目的规划一切以用户需求为导向&#xff0c;首先需要明确各层次的需求用户。用户都不能明确&#xff0c;调研的入口就没…

前端工程化与 webpack:webpack 的基本使用

1. 什么是 webpack 概念&#xff1a;webpack 是前端项目工程化的具体解决方案。 主要功能&#xff1a;它提供了友好的前端模块化开发支持&#xff0c;以及代码压缩混淆、处理浏览器端 JavaScript 的兼容性、性 能优化等强大的功能。 好处&#xff1a;让程序员把工作的重心放…

自动控制原理笔记-信号流图-Mason公式-控制系统的传递函数

目录 信号流图与结构图的比较&#xff1a; 掌握结构图与信号流图的转换&#xff1a; Mason增益公式&#xff1a; 式子详解&#xff1a; 使用Mason增益公式步骤&#xff1a; 使用Mason增益公式的例题&#xff1a; ​编辑 控制系统的传递函数 &#xff1a; 开环传递函数…

当红齐天再捧“绽放杯”金奖:全流程算力网络夯实元宇宙“底座”

近日&#xff0c;由工信部主办的第五届“绽放杯”5G应用征集大赛在深圳落幕。本届大赛以“5G赋能数字化&#xff0c;扬帆助力新征程 ”为主题&#xff0c;超7000家单位的2.8万个项目参赛&#xff0c;共享5G赋能实体经济的新技术、新成果。英特尔联合行业合作伙伴再获佳绩。 其…

java ssm热带水果网上商城系统--

目录 第一章 绪论 5 1.1 研究背景 5 1.2系统研究现状 5 1.3 系统实现的功能 6 1.4系统实现的特点 6 1.5 本文的组织结构 6 第二章开发技术与环境配置 7 2.1 Java语言简介 7 2.2JSP技术 8 2.3 MySQL环境配置 8 2.4 MyEclipse环境配置 9 2.5 mysql数据库介绍 9 2.6 B/S架构 9 第三…

Matter理论介绍-通用-1-06:桥接设备-其他功能

【源码、文档、软件、硬件、技术交流、技术支持&#xff0c;入口见文末】 【所有相关IDE、SDK和例程源码均可从群文件免费获取&#xff0c;免安装&#xff0c;解压即用】 持续更新中&#xff0c;欢迎关注&#xff01; 一、桥接设备的功能更新 桥接设备能够独立与桥接器进行软…

一文带你快速搭建框架(最全MyBatis笔记修改篇)

前言&#xff1a;最近收到小伙伴们的私信说这一篇有点问题&#xff0c;因为我是用Typora搬运笔记没考虑到这个问题&#xff0c;感谢这个小伙伴反映的问题~ 目录 一.概述 1.简介 2.maven构建 二.相关概念 1.Mapper接口 2.ORM思想 三.映射配置文件 1.文件结构 2.映射配…