伸展树(数据结构篇)

news2024/9/20 20:33:56

数据结构之伸展树

伸展树

概念

  • 伸展树是一颗对任意一个节点被访问后,就经过一系列的AVL树的旋转操作将该节点放到根上的特殊二叉查找树
  • 伸展树能保证对树操作M次的时间复杂度为O(MlogN),而当一个查找树的一个节点刚好处于查找树最坏的情形,我们每次访问都需要按照最坏情形的时间计算,这将耗费O(M*N)的时间,伸展树就是要将访问的节点进行移动,使它不一直存在一个地方,避免了多次操作最坏情形的出现,而伸展树访问的节点比较深,经过移动,对该节点的原先子树节点访问也会避免往更深处进行操作
  • 伸展树不要求保留高度或平衡信息,因此能够节省空间以及简化代码

查找操作

  • 关于访问节点,然后对其进行一系列旋转操作,将该节点放到上,我们需要对访问该节点的路径上(从下到上)每一个节点都需要和它们的父节点实施单旋转,直到将该节点推到根

  • 但是如果只进行单旋转情况,并直接从下到上的话,则会浪费大部分时间

  • 因此我们需要使用展开操作,而展开操作其实就是根据路径树的结构分情况进行操作

  • 具体步骤

    1. 判断路径的结构,分为“之字形”和“一字形
    2. 如果是“之字形”,就需要对要访问的节点进行双旋转操作,如果访问的节点不是根的孙节点,则进行双旋转操作后,会将路径结构转换为“一字形”,然后再进行“一字形”操作,将其放在根上
    3. 如果是“一字形”,就需要路径从下到上逐一进行单旋转操作,直至要访问的节点成为根才结束

    image

删除操作

  • 我们可以通过访问要被删除的节点然后访问后进行删除,这样的话,被删除节点就会被推到根上,将该节点删除,树就会分为两颗子树TL和TR(左子树和右子树)
  • 要想将TL和TR重新合成为一个树,就需要找到TL的最大值,并进行旋转操作将其作为TL的根节点,而此时T**L将是一个没有右儿子的树**,然后将TR的根节点作为现在TL根节点的右儿子

代码:

struct splay{
    int data;
    splay* left;
    splay* right;
};

splay* createNode(int data){
    auto p=new splay;
    p->data=data;
    p->left=NULL;
    p->right=NULL;
    return p;
}

splay* SingleRotatewithLeft(splay* &k1){
    splay* k2;
    k2=k1->left;
    k1->left=k2->right;
    k2->right=k1;
    return k2;
}

splay* SingleRotatewithRight(splay* &k1){
    splay* k2;
    k2=k1->right;
    k1->right=k2->left;
    k2->left=k1;
    return k2;
}

splay* DoubleRotatewithLeft(splay* &k1){
    k1->left= SingleRotatewithRight(k1->left);
    return SingleRotatewithLeft(k1);
}

splay* DoubleRotatewithRight(splay* &k1){
    k1->right= SingleRotatewithLeft(k1->right);
    return SingleRotatewithRight(k1);
}

//插入
splay* insert(splay* &root,int data){
    if(NULL==root){
        splay* add= createNode(data);
        root=add;
    }else if(data<root->data){
        root->left= insert(root->left,data);
    }else if(data>root->data){
        root->right= insert(root->right,data);
    }
    return root;
}

//查找
//因为查找data很有可能是相等的,所以要分开这种情况,如果root的下一个是要找的我们就往上返,令节点差为2个保证了判断路径结构的正确性
splay* search(splay* &root,int data){
    if(NULL==root||root->data==data){
        return root;
    }else if(data<root->data){
        root->left= search(root->left,data);
        if(data<root->left->data){
            root= SingleRotatewithLeft(root);
        }else if(data>root->left->data){
            root= DoubleRotatewithLeft(root);
        }
    }else if(data>root->data){
        root->right= search(root->right,data);
        if(data>root->right->data){
            root= SingleRotatewithRight(root);
        }else if(data<root->right->data){
            root= DoubleRotatewithRight(root);
        }
    }
    return root;
}

//查找最小值
int findmin(splay* root){
    if(NULL==root){
        return root->data;
    }
    if (root->left!=NULL){
        return findmin(root->left);
    }else{
        return root->data;
    }
}

//查找最大值
int findmax(splay* root){
    if(NULL==root){
        return root->data;
    }
    if(root->right!=NULL){
        return findmax(root->right);
    }else{
        return root->data;
    }
}

//删除树节点
void del(splay* &root,int data){
    search(root,data);
    if(NULL==root){
        return;
    }else{
        splay* t1=root->left;
        splay* t2=root->right;
        root->left=NULL;
        root->right=NULL;
        delete root;
        int temp= findmax(t1);
        t1= search(t1,temp);
        t1->right=t2;
        root=t1;
    }
}

void inorderprint(splay* root){
    if(NULL==root){
        return;
    }
    inorderprint(root->left);
    cout<<root->data<<" ";
    inorderprint(root->right);
}

//清空树
void destroy(splay* &root){
    if(NULL==root){
        return;
    }
    destroy(root->left);
    destroy(root->right);
    delete root;
}

尾言

完整版笔记也就是数据结构与算法专栏完整版可到我的博客进行查看,或者在github库中自取(包含源代码)

  • 博客1: codebooks.xyz
  • 博客2:moonfordream.github.io
  • github项目地址:Data-Structure-and-Algorithms

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

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

相关文章

Vite: 关于预构建的毫秒级响应

概述 在我们的项目代码中&#xff0c;我们所说的模块代码其实分为两部分 一部分是源代码&#xff0c;也就是业务代码另一部分是第三方依赖的代码&#xff0c;即 node_modules 中的代码 Vite 是一个提倡 no-bundle 的构建工具&#xff0c;相比于传统的 Webpack能做到开发时的模…

主机游戏也可以上云桌面玩了?

最近steam夏季促销活动也快到了&#xff0c;对于很多钟情于主机游戏的小伙伴们&#xff0c;是不是也在摩拳擦掌了&#xff1f; 但有时候现实想愉快地玩到自己想玩的游戏实在是太难了&#xff01; 当你一直关注的新游戏终于上线Steam时&#xff0c;你的钱包是这样的… 而游戏的…

elementUI相关知识及搭建使用过程

​​​​​​ 目录 ​​​​​​ 一.elementUI相关的知识 1.什么是elementUI 2.如何在创建的项目中使用elementUI的组件(1)安装 ​ (2)在项目的main.js中引入elementUI (3)使用elementui里的组件 一.elementUI相关的知识 1.什么是elementUI Element&#xff0c;一套为开…

【管理咨询宝藏136】RB大型卡车集团供应链体系优化设计方案

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏136】RB大型卡车集团供应链体系优化设计方案 【格式】PDF版本 【关键词】罗兰贝格、供应链管理、运营提升 【核心观点】 - 针对前两个模块&…

Charles配置与API数据抓取

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;-CSDN博客跳槽涨薪的朋友们有福了&#xff0c;今天给大家推荐一个软件测试面试的刷题小程序。https://blog.c…

基于STM32的智能健康监测手表

目录 引言环境准备智能健康监测手表系统基础代码实现&#xff1a;实现智能健康监测手表系统 4.1 数据采集模块4.2 数据处理与分析4.3 通信模块实现4.4 用户界面与数据可视化应用场景&#xff1a;健康监测与管理问题解决方案与优化收尾与总结 1. 引言 智能健康监测手表通过使…

美团SaaS技术部测开,复捞我开摆

美团SaaS技术部测开&#xff0c;复捞我开摆 4.3 80min 项目实习你主要承担的部分你做的项目技术实现是什么样的&#xff0c;前后端是怎么做出来的自动登录功能的架构软件测试全流程你有了解吗搭建测试环境是否可有可无哪些举措是你牵头做的发现了什么问题在代码核验阶段你如何…

C++STL梳理

CSTL标准手册&#xff1a; https://cplusplus.com/reference/stl/ https://cplusplus.com/reference/vector/vector/at/ 1、STL基础 1.1、STL基本组成(6大组件13个头文件) 通常认为&#xff0c;STL 是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成&…

【消息队列】Kafka学习笔记

概述 定义 传统定义: 一个分布式的, 基于发布订阅模式的消息队列, 主要应用于大数据实时处理领域新定义: 开源的分布式事件流平台, 被用于数据管道/流分析/数据集成 消息队列的使用场景 传统消息队列的主要应用场景包括: 削峰: 解耦: 异步: 两种模式 点对点模式 发布/订…

Java基础:IO流

目录 一、定义 1.引言 2.分类 &#xff08;1&#xff09;按照流的方向分 &#xff08;2&#xff09;按操作文件的类型分 3.体系结构 二、字节流&#xff08;以操作本地文件为例&#xff09; 1. FileOutputStream 类 &#xff08;1&#xff09;定义 &#xff08;2&am…

【Linux】Linux编译器(gcc,g++)与动静态链接库

对于一个 C 程序&#xff0c;从源文件到形成可执行程序一共要进行四步&#xff1a;预处理、编译、汇编、链接 。 接下来&#xff0c;我们用 gcc 分别演示这四个过程。 一、预处理(进行宏替换) 预处理中&#xff0c;需要完成头文件的展开、宏替换、去注释、条件编译等工作。 …

说一说三大运营商的流量类型,看完就知道该怎么选运营商了!

说一说三大运营商的流量类型&#xff0c;看完就知道该怎么选运营商了&#xff1f;目前三大运营商的流量类型大致分为通用流量和定向流量&#xff0c;比如&#xff1a; 中国电信&#xff1a;通用流量定向流量 电信推出的套餐通常由通用流量定向流量所组成&#xff0c;通用流量…

《数字图像处理》实验报告一

一、实验任务与要求 1、用 matlab 编写空间域点处理操作处理给定的几幅图像&#xff0c;要求&#xff1a; 使用 imread 读取当前工作目录下的图像设计点处理操作并用代码实现处理用 imnshow 显示处理后的图像用 imwrite 保存处理后的图像 2、提交内容&#xff1a;m文件 实验…

假冒国企现形记:股权变更视角下的甄别分析

启信慧眼-启信宝企业版 假冒国企公告2024-06-07&#xff0c;中粮集团有限公司官网发布《关于冒名中粮企业名单公告》。公告显示&#xff0c;”有不法分子通过伪造相关材料等方式&#xff0c;以我集团子公司名义开展业务&#xff0c;进行虚假宣传。经核实&#xff0c;上述公司假…

【SpringCloud】API网关(Spring Cloud Gateway)

本文基于上一篇http://t.csdnimg.cn/q3YrK 使用抽取的方案使用feign的基础上使用Spring Cloud Gateway。 API网关 API网关&#xff08;简称网关&#xff09;也是一个服务&#xff0c;通常是后端服务的唯一入口。它就像是整个微服务架构的门面&#xff0c;所有的外部客户端访问…

Python学习笔记13:进阶篇(二),类的继承与组合

类的继承 我们在编写一系列的类的时候&#xff0c;会发现这些类很相似&#xff0c;但是又有各自的特点和行为。在编写这些类的时候&#xff0c;我们可以把相同的部分抽象成一个基类&#xff0c;然后根据其他不同的特点和行为&#xff0c;抽象出子类&#xff0c;继承这个基类。…

python实训day4

1、查看数据库的版本 2、查看当前用户 3、查看当前数据库 4、计算表达式的结果; 任何一个数据库,无论大小,都首先是一个超级计算器 5、查看当前MySQL环境中所有的数据库; 系统数据库(只能看)和自定义数据库(任何操作) 6、先建数据库 gaoming 7、如果表已经存在,则创建不能成功 …

刷题之小欧的平均数(卡码网)

小欧的平均数 这道题不看解析的话完全没有思路&#xff0c;连题目都没读明白&#xff0c;甚至看了评论答出来了还是不知道为什么&#xff0c;有知道的朋友可以教教我 #include<iostream> using namespace std;int main() {int x,y,z;cin>>x>>y>>z;//…

oracle12c到19c adg搭建(六)切换后12c备库服务器安装19c软件在19c主库升级数据字典后尝试同步

一、安装19c软件 参考文章oracle12c到19c adg搭建&#xff08;三&#xff09;oracle19c数据库软件安装 二、原主库尝试通过19c软件启动数据库 2.1复制12c的相关参数文件和密码文件到19c目录 注意:密码文件需要从已切换主库19c传过来 [oracleo12u19p ~]$ cd /u01/app/oracle…

亲测有效!性能压测异常竟能自动化分析!

性能压测是一种评估系统运行效率和稳定性的方法&#xff0c;通过模拟真实的使用场景和负载条件&#xff0c;对系统进行压力测试和负载测试&#xff0c;并对测试结果进行分析&#xff0c;以评估系统的性能&#xff0c;其中性能压测结果分析是性能压测的重要环节。以往的性能压测…