JAVA之伸展树

Java进阶:17.3 伸展树 1、伸展树简介 伸展树(Splay Tree)是特殊的二叉查找树(BST)。 它的特殊是指,它除了本身是棵二叉查找树之外,它还具备一个特点: 当某个节点被访问时,伸展树会通过旋转使该节点成为树根。这样做的好处是,下次要访问该节点时,能够迅速的访问到该节点。 通过之前的学习,知道连续m次查找,对于AVL树来说,共需要O(mlogn)时间。根据局部性原理,我们可以改进AVL树!!-----> 引... 阅读详情
  • 伸展树与二叉平衡查找树
    AVL树(带有平衡条件的树)查找的时候最坏的情形为0(N)并不坏,只要它不经常发生就可以。任何一次访问,即使花费0(N),任然可能非常快。具有最坏运行时间0(N)但保证对任意M次连续操作最多花费O(MlogN)运行时间确实让人满意了。
    伸展树和其它树的区别就是没访问一个节点的时候,那个节点就会成为根节点,这样下次访问的时候时间为0(1)并且与二叉平衡查找树比少了高度的属性和判断平衡信息,因此从某种程度上简化代码。

在伸展树中最主要的一部分就是伸展,分为两种情况第一种是之字形(zig-zag)情形,第二种就是一字形(zig-zig)
这里写图片描述
这里写图片描述

package tree;


/*
 * 伸展树:他保证从空树开始连续M次对树的操作最多花费0(MlogN)时间
 */
public class STree<AnyType extends Comparable<? super AnyType>>{
    private Node root;
    private class Node{
        public Node left;//左孩子
        public Node right;//右孩子
        public Node parent;//父亲节点
        public AnyType x;//data数据

        public Node(AnyType x){
            this.x = x;
            parent = null;
            left = null;
            right = null;
        }
    }

    public STree(){
        root = null;
    }

    //查找
    public AnyType find(AnyType key){
        root = find(root, key);
        if(root == null || root.x.compareTo(key) != 0) return null;
        return root.x;
    }

    private Node find(Node p, AnyType key){
        if(p == null || key == null) return null;
        Node prep = null;
        while(p != null){
            prep = p;
            int cmp = key.compareTo(p.x);
            if(cmp < 0) p = p.left;
            else if(cmp > 0) p = p.right;
            else break;
        }
        root = splay(prep);
        return root;
    }

    //插入
    public void insert(AnyType data){
        if(data == null) return;
        if(root == null){
            root = new Node(data);
            return;
        }
        Node t = find(root, data);
        int cmp = data.compareTo(t.x);
        if(cmp == 0){//更新value
            root.x = data;
            return;
        }
        root = new Node(data);
        //先把T分为左右子树,再合并
        if(cmp < 0){//插入新根,以t->lchild和t为左/右孩子
            Node x = t.left;
            root.left = x;
            root.right = t;
            t.parent = root;
            if(x != null){
                x.parent = root;
                t.left = null;
            }
        }else if(cmp > 0){
            Node x = t.right;
            root.left = t;
            root.right = x;
            t.parent = root;
            if(x != null){
                x.parent = root;
                t.right = null;
            }
        }
    }

    //删除
    public void delect(AnyType key){
        if(key == null) return;
        Node t = find(root, key);
        if(t == null || key.compareTo(t.x) != 0)
            return;

        if(t.right == null){//右子树为空
            root = root.left;
            root.parent = null; return;
        }
        //右子数不空
        //1.删除T节点, 得到子树tl, tr
        Node tl = t.left, tr = t.right;
        tr.parent = null;
        //2.将右子树最小节点min伸展至右子树树根,min一定没有左子节点
        Node min = min(tr);
        //3.将tl作为左子树链接到min上
        min.left = tl;
        if(tl != null) tl.parent = min;
        root = min;
    }

    public AnyType min(){
        if(root == null)    return null;
        root = min(root);
        return root.x;
    }

    private Node min(Node x){
        if(x == null)   return null;
        while(x.left != null)
            x = x.left;
        x = splay(x);
        return x;
    }

    public AnyType max(){
        if(root == null)    return null;
        root = max(root);
        return root.x;
    }
    private Node max(Node x){
        if(x == null) return null;
        while(x.right != null)
            x = x.right;
        x = splay(x);
        return x;
    }

    private Node splay(Node v){//v是找到的节点
        if(v == null) return null;
        Node p, g; //v的父亲与祖父
        //自上而下,反复对v做双层伸展
        while((p = v.parent) != null && (g = p.parent) != null){
            Node gg = g.parent;//(great-grand parent)为父
            if(isLChild(v)){
                if(isLChild(p)){//zig-zig(g)先g结点右旋,zig(p)在p右旋
                    attachAsLChild(g, p.right);
                    attachAsRChild(p, g);
                    attachAsLChild(p, v.right);
                    attachAsRChild(v, p);
                }else{//zig-zag(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结点左旋,zig(p)再p左旋
                    attachAsRChild(g, p.left);
                    attachAsLChild(p.left, 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
                attachAsRChild(p, v.right);
                attachAsRChild(v, p);
            }else{//zag
                attachAsRChild(p, v.left);
                attachAsLChild(v, p);
            }
        }
        v.parent = null;
        return v;
    }

    //判断n是否是父节点的左孩子
    private boolean isLChild(Node n){
        Node p = n.parent;
        return p.left == n;
    }
    //判断n是否是父节点的右孩子
    private boolean isRChild(Node n){
        Node p = n.parent;
        return p.right == n;
    }
    //在节点p与rc(可能为空)之间建立父(左)子关系
    private void attachAsLChild(Node parent, Node lchild){
        parent.left = lchild;
        if(lchild != null)
            lchild.parent = parent;
    }
    //在节点p与rc(可能为空)之间建立父(右)子关系
    private void attachAsRChild(Node parent, Node rchild){
        parent.right = rchild;
        if(rchild != null)
            rchild.parent = parent;
    }

    public void prearder(){
        prearder(root);
        System.out.println("前序遍历");
        System.out.println();
    }
    private void prearder(Node p){
        if(p == null) return;
        System.out.print(p.x+" ");
        prearder(p.left);
        prearder(p.right);
    }

    //测试
    public static void main(String[] args){
        STree<Integer> st = new STree<Integer>();
        for(int i=0; i<10; i++)
            st.insert(i);

        st.find(5);
        st.prearder();
    }
}
用《Flappy Bird》游戏带你搞懂强化学习:从Q-learning到DQN的保姆级实战 本文通过《Flappy Bird》游戏实战,详细讲解了从Q-learning到DQN的强化学习技术。从环境搭建、Q表格构建到深度Q网络(DQN)的实现,逐步展示如何训练AI自主玩游戏。文章包含代码示例、训练技巧和性能优化方法,帮助读者深入理解强化学习的核心概念和应用。 阅读详情

相关推荐

Unity物理驱动3D汽车实现:从刚体控制到参数调优

在游戏开发中,刚体物理是实现真实物体运动与交互的核心技术。通过Unity的物理引擎,开发者可以模拟重力、碰撞、摩擦力等物理行为,为游戏世界注入真实感。其技术价值在于能够以符合物理规律的方式驱动游戏对象,避免穿墙、无视惯性等问题,从而提升游戏体验的真实性和沉浸感。这一原理广泛应用于角色控制、车辆模拟、物体破坏等场景。本文以3D小汽车为例,详细解析了如何通过Rigidbody组件施加力与扭矩,并利用C#脚本实现玩家输入逻辑,完成一辆可操控、能碰撞的物理驱动汽车。文中重点探讨了AddForce与角速度控制两种方案

weixin_34380948的博客 500

Tree | 伸展树

本文目录 一、伸展树的基本概念 二、Splay —— 伸展操作的原理 1、P 是根节点 2、P 不是根节点 Z字型旋转(Zig-zag) 一字型旋转(Zig-zig)—— 左 一字型旋转(Zig-zig)—— 右 三、伸展操作的实现 四、利用伸展树实现其他操作 1、Find(x,S) 2、Insert(x,S) 3、Delete(x,S) 4、Join(S1,S2) ...

weixin_43787043的博客 662

Camera AF和FF

Camera按对焦功能可以分为FF(Fixed Focus)和AF(Auto Focus),即固定对焦和自动对焦。固定对焦顾名思义就是焦距是固定的,而自动对焦可以通过移动镜头位置来改变焦距从而实现自动对焦。以前摄像的功能机大多是固定对焦,现在的手机都带有自动对焦功能。 FF模组包括镜头(Lens),传感器(Sensor),红外滤色器(IR Filter),电路板(PCB),镜头支撑(Lens Holder),连接器(Connector)。 Fig 1. FF Module AF模组包括FF模组,音圈马达(V

Coppa的博客 1万+

splay学习小记

高大上的splay。 让我splay一下先。好了,讲正事。(所有图片来自wiki,感谢大力支持) splay,顾名思义,就是伸展树。它是二叉排序树的一种。然后,为了完成一些操作,它会通过不断旋转来在不破坏结构的情况下调整自身,从而减小深度,达到log n的均摊复杂度。可以说,splay的核心就是这O2(氧气)的旋转。如何旋转?首先,可以很容易的想到,左旋和右旋的打法。 但是,如果原来的树是

时光真疯狂, 我一路执迷于匆忙. 997

从贝叶斯网络到结构因果模型:因果推理在可解释AI中的实践

在机器学习和数据分析领域,理解变量间的因果关系而不仅仅是统计关联,是构建可信赖、可解释系统的关键。概率图模型,特别是贝叶斯网络,通过有向无环图和条件概率表,能够高效地编码和推理变量间的条件依赖关系,广泛应用于医疗诊断、风险评估等场景。然而,贝叶斯网络主要刻画的是“是什么”的关联,难以回答“如果…会怎样”的因果问题。为了进行因果推断,需要引入结构因果模型和do-演算,它们通过定义结构方程和模拟干预操作,能够区分混杂效应,估计处理变量对结果变量的净因果影响。这一套方法论对于可解释人工智能至关重要,它能生成反事实

weixin_42168902的博客 379

1.47寸ST7789V3彩屏硬件设计与驱动调试指南

TFT LCD是一种基于薄膜晶体管阵列控制像素明暗的主动式显示技术,其核心依赖于专用驱动IC(如ST7789V3)完成时序生成、GRAM管理与伽马校正。该类小尺寸彩色显示屏广泛应用于嵌入式HMI、IoT终端与可穿戴设备,具备高PPI、低功耗和SPI接口易集成等工程优势。理解RGB565数据格式、SPI Mode 0通信时序及关键寄存器(如0x36方向控制、0x3A像素格式、0x2A/0x2B地址窗口)是实现稳定显示的基础;而正确处理电源设计(严禁5V直供)、复位时序与背光PWM调光,则直接决定系统可靠性与能

weixin_30995917的博客 165

Day15

这两天学习的欲望特别的。。。弱,脑子说“我转不动了,我不想转了,我想玩游戏”,心里说“才这么几天就放弃,年后依然找不到工作,没有钱哪有钱买游戏?” (╯‵□′)╯︵┻━┻ 在一番激烈斗争后,双方决定从心,能多学一点儿是一点儿吧,谁让以前总是脑子赢的下场不太好呢(╯‵□′)╯︵┻━┻。。。 伸展树 平衡二叉搜索树的一种形式,无需时刻严格保持全树的平衡,却能够在足够长的真实序列中保持分摊意义上的...

不甘心的菜鸟 329

微信小程序 - error_msg:net::ERR_CONNECTION_RESET“(“errno“:600001,“errMsg“:“uploadFile:fail errcode:-101)

"errno":600001,"errMsg":"uploadFile:fail errcode:-101 cronet_error_code:-101 error_msg:net::ERR_CONNECTION_RESET"微信小程序,微信小程序wx.uploadFile报错,uniapp微信小程序uni.uploadFile上传文件报错,微信小程序调用wx.uploadFile返回错误ERR_CONNECTION_RESET,如何解决这个问题,上传图片出现报错,小程序上传视频报错,上传文件出现报错,如何

🏆 前端领域优质创作者 5408

伸展树

伸展树,是一种二叉排序树。它可以baozheng

flyapy 840

096、PCIE环回模式(Loopback):调试时自己和自己对话的利器

摘要: PCIE环回模式是调试利器,通过让芯片内部数据自环来定位问题层级。文章详解三种环回模式:物理层环回验证基础收发,数据链路层环回测试DLLP机制,事务层环回验证端到端协议。分享了实战中的典型问题(时钟异常、状态机卡死、计数器失真)和"从下往上"的调试流程,强调要区分调试与生产功能,建议早期验证环回模式。通过具体代码示例和调试案例,说明合理使用环回模式能显著提升排查效率,是PCIE调试必备技能。(149字)

z534437748的博客 105

github创建账号第一步始终出错

github创建账号总结:第一次注册GitHub,填好用户名邮箱密码后进入下一步就卡在哪里,上面还提示Unable to verify your captcha response等,进入网址的解决办法以及下载其他的浏览器也无法解决,用手机浏览器抱着试一试的心态竟然成功了,分享给大家。手机下载谷歌浏览器,进入GitHub正常注册,能向下继续,邮箱验证完以后再用电脑登陆就ok啦

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 4373

伸展树c++ 实现

一、为什么要有伸展树 根据

chance_yin 3568

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

伸展树 之 Java的实现

伸展树的介绍伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由Daniel Sleator和Robert Tarjan创造。 (01) 伸展树属于二叉查找树,即它具有和二叉查找树一样的性质:假设x为树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果

Code-lover's Learning Notes 1322

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

数据结构 - 伸展树的Java实现

数据结构 - 伸展树的Java实现 阅读本节前请先阅读上一篇文章:https://blog.csdn.net/funnyrand/article/details/81745518,该文章讲述了AVL树的原理和Java实现。需要理解AVL树的4种旋转方式及原理。 一、简介 伸展树(Splay Tree)是特殊的非平衡二叉查询树,它的特殊性是指,它除了本身是棵二叉查询树之外,它还具备一个特点: ...

尘世中迷途小码农的专栏 1340

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

splay tree java移除_伸展树(三)之 Java的实现

概要前面分别通过C和C++实现了伸展树,本章给出伸展树的Java版本。基本算法和原理都与前两章一样。1.2.3.伸展树的介绍伸展树(Splay Tree)是特殊的二叉查找树。它的特殊是指,它除了本身是棵二叉查找树之外,它还具备一个特点: 当某个节点被访问时,伸展树会通过旋转使该节点成为树根。这样做的好处是,下次要访问该节点时,能够迅速的访问到该节点。伸展树的Java实现1. 基本定义public ...

weixin_35562225的博客 363

【数据结构与算法】JAVA实现 自定向下的伸展树

文章目录JAVA实现自定向下的伸展树自定向下的伸展树的原理代码实现 JAVA实现自定向下的伸展树 主要是记录自己的内容,具体原理可能不够详细,代码可供参考。 自定向下的伸展树的原理 原理参考 书《数据结构与算法分析:JAVA语言描述》P356 和 自定向下的伸展树的原理 代码实现 package chapter12; import chapter04.MyCustomException; public class SplayTree<T extends Comparable<? super

大枫树 380

splay tree.java_伸展树--Java实现

前言前面的学习中,笔者就二叉树、二叉查找树、平衡二叉树进行了一些总结。此篇文章主要讨论伸展树。我们知道的是在二叉查找树上的基本操作(查找、插入)的时间复杂读与树的高度成正比的关系。对于一个含有N个结点的二叉查找树来说,这些操作的最坏运行情况为OlogN)。但是我们这知道在极端的情况下,会导致树退化为一个单支树,这导致了操作时间为O(N)。为了克服上面的情况,出现了一些二叉查找树的变形,例如上篇文章...

weixin_36124888的博客 461

伸展树(三)之 Java的实现

概要 前面分别通过C和C++实现了伸展树,本章给出伸展树的Java版本。基本算法和原理都与前两章一样。1.伸展树的介绍2.伸展树的Java实现(完整源码)3.伸展树的Java测试程序 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3604286.html 更多内容:数据结构与算法系列 目录 (01)伸展树(一)之...

kk的博客 266

splay tree.java_伸展树--java

文字转载自:http://www.cnblogs.com/vamei代码转载自:http://www.blogjava.net/javacap/archive/2007/12/19/168627.html我们讨论过,树的搜索效率与树的深度有关。二叉搜索树的深度可能为n,这种情况下,每次搜索的复杂度为n的量级。AVL树通过动态平衡树的深度,单次搜索的复杂度为log(n) (以上参考纸上谈兵 AVL树...

weixin_36285931的博客 255

伸展树--Java实现

前言 前面的学习中,笔者就二叉树、二叉查找树、平衡二叉树进行了一些总结。此篇文章主要 讨论伸展树。我们知道的是在二叉查找树上的基本操作(查找、插入)的时间复杂读与树的高度 成正比的关系。对于一个含有N个结点的二叉查找树来说,这些操作的最坏运...

weixin_34408717的博客 175

[Loj.ac-java] Splay - 伸展树(分裂树)

问题: 说明: https://oi-wiki.org/ds/splay/ 来 写 一 个 Splay。 问题链接:https://loj.ac/problem/104 提交记录: https://loj.ac/submission/884459 输入案例: 传了一份测试数据:https://download.csdn.net/download/qq_28033719/12609664(假装骗积分) 我的代码: 准备知识 1、以往知识: 左旋转 右旋转前驱 后继https://...

qq_28033719的博客 450

伸展树Java实现

特性 伸展树(Splay Tree)是特殊的二叉查找树,当某个节点被访问时,伸展树会通过旋转使该节点成为树根。 树结点和构造函数 public class SplayTree<T extends Comparable<T>> { private class SplayTreeNode<T extends Comparable<T>> { ...

weixin_34128237的博客 258

一个伸展树的实现

伸展树实现(java语言版本) 一、伸展树的基本概念 伸展树是一种二叉搜索树,伸展树也是一种平衡树,不过伸展树并不像AVL树那样对树的平衡有很严格的要求(左右孩子高度之差不能超过1),伸展树通过一系列的伸展操作,可以保证对伸展树的任意连续M次操作,其时间复杂度不会超过MlogN级别,并且伸展树的实现相较于AVL树也简单了很多,不论是插入还是删除算法 二、伸展树的伸展操作 伸展树之所以能够保证MlogN的界,就是因为伸展树的伸展操作,每一次调用伸展树的search方法查找一个结点的时候,如果存在,那么就

西城风雨楼 737

Java基础 - 伸展树(SplayTree)

伸展树的基本操作有: 1.查询 2.添加 3.删除 4.树的最大节点 5.树的最小节点 6.节点的前驱 7.节点的后继 8.合并 9.分离 下面是我完成的部分功能代码(除节点的后继,大家可以仿照求节点的前驱的方法来求后继,很简单): package com.yc.tree; import java.util.ArrayDeque; import java.util.Arra

ApatheCrazyFan的博客 2119

Java数据结构07_伸展树

1、介绍   伸展树与平衡树(AVL树、红黑树)一样,都是对二叉查找树的一种改进数据结构,它的主要特点是不会保证树一直是平衡的,但各种操作的平摊时间复杂度是O(logn),并且相对平衡树而言,伸展树还不要求保留高度或者平衡信息,编码复杂度要小很多;   伸展树是基于这样一个事实:对于二叉查找树而言,每次操作最坏情形时间O(N)并不坏,只要它相对不常发生就行,并且保证对任意M次连续操作最多花费O(Mlogn)运行时间;基于这个事实,伸展树的基本想法是,认为许多应用中当一个节点被访问后,它很可能不久再被访问,所

weixin_43370748的博客 277
上一篇: JAVA之查找二叉平衡树
下一篇: 数据结构排序之插入排序
LuFei_java
博客等级 码龄10年 1粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值