伸展树学习总结

伸展树

与AVL树类似, 伸展树也是二叉搜索树的一种形式, 伸展树无需保证时刻保持全树的平衡,也不需要像AVL树一样要求记录平衡因子的附加信息
伸展树的提出源于信息访问的局部性(刚被访问过的信息有可能再次被访问,要被访问的元素可能位于刚访问过的元素的附近), 就伸展树而言,可采用刚被访问的元素移至数据列表的前端,从而降低后续的操作时间

简易伸展树的最坏情况
每次使用search,将访问后的元素移至树根节点, 如果采用单次zig/zag旋转(先对该节点的父节点进行旋转,再对祖父进行旋转,每旋转一次,节点上升一层), 如果总节点数为n,那么总的旋转次数将高达O(n*n), 平摊到每个节点,复杂度(O(n))都高于AVL树, 简易伸展并不会改变当前树的拓扑结构
如图:
这里写图片描述

双层旋转
由于单层旋转将会造成O(n)多,高于AVL树,就此提出改进措施:
进行双层旋转, 每次的旋转不再是从当前节点的parent开始,而是从当前节点的grandpa开始;先对g旋转,再对p旋转,这种旋转方式将在zig-zig,zag-zag下展现效果,如图
这里写图片描述
对比简易伸展与双层旋转,将会发现双层旋转每进行一次search操作, 那么树的高度将会折半,那么如果访问最坏的节点也不会出现O(n)的复杂度,单次操作可在O(logn)时间内完成, 但是如果旋转方式为zig-zag/zag-zig, 双层旋转并不能改变树高,双层旋转将导致树的拓扑结构发生改变
有一种情况为:可能在最后的双层旋转过程中,v只有parent而没有grandpa,但是这种情况只会在最后出现,并且只出现一次,所以并不会影响树的整体旋转效果,因此双层旋转的方式是有效的

伸展树接口定义
基于二叉平衡搜索树类,重写search()(查找过程也会改变树的拓扑结构,所以有必要进行重写), insert(), remove()接口
伸展树的伸展调整算法:

template<typename T>inline void attachAsLChild(NodePosi p, NodePosi lc){p->lChild=lc;if(lc)lc->parent=p;//为p,lc建立父(左)子的关系,可能lc为null
}
template<typename T>inline void attachAsRChild(NodePosi p, NodePosi rc){p->rChild=rc;if(rc)rc->parent=p;//为p,lc建立父(左)子的关系,可能lc为null
}template<typename T>BinNodePosi* Splay<T>::splay(BinNodePosi* v){//从v的位置开始进行伸展操作if(!v) return null;BinNodePosi* p,g;//v的父亲与祖父while((p=v->parent)&&(g=p->parent)){//自下而上进行双层伸展BinNodePosi* gg=g->parent;if(p->lChild==v)if(g->lChild==p){//zig-zig//忽略具体旋转过程,直接拼接操作attachAsLChild(g,p->rChild);//将g拼接到p上attachAsLChild(p,v->rChild);//将p拼接到v上attachAsRChild(p,g);attachAsRChild(v,p);//操作同上}else{//zig-zagattachAsLChild(p,v->rChild);attachAsRChild(g,v->lChild);attachAsLChild(v,g);attachAsRChild(v,p);}else if(g->RChild==p){//zag-zagattachAsRChild(g,p->lChild);attachAsRChild(p,v->lChild);attachAsLChild(p,g);attachAsLChild(v,p);} else{//zag-zigattachAsRChild(p,v-lChild);attachAsLChild(g,v->rChild);attachAsRChild(v,g);attachAsLChild(v,p);}if(!gg) v->parent=null;//v伸展至最顶端,变为rootelse//曾祖父存在,直接将v作为曾祖父的左孩子或右孩子(g==gg->lChild)?attachAsLChild(gg,v):attachAsRChild(gg,v);updateHeight(g);updateHeight(p);updateHeight(v);}if(p=v->parent){//v旋转到最后还有一个p,需要完成一次单旋if(p-lChild==v){attachAsLChild(p,v->rChild);attachAsRChild(v,p);}else           {attachAsRChild(p,v->lChild);attachAsLChild(v,p);}updateHeight(p);updateHeight(v);}v->parent=null; returnv;//v已移至root位置
}

search实现

//在search过程中,将节点移动
template<typename T>BinNodePosi* Splay<T>::search(const T& e){BinNodePosi* p=searchIn(_root,e,_hot=null);//从根节点位置开始查找_root=splay((p?p:root));//无论查找是否成功都将返回与之对应的那个节点或者相似的节点至_root位置return _root;
}

insert实现

//由于查找的过程中就实现了将要找的相似元素移动至_root位置,再将要插入的元素与root位置的节点作比较,节点重连实现插入操作
template<typename T>BinNodePosi* Splay<T>::insert(const T& e){if(!_root) {++_size; return _root= new BinNode<T>(e);}//为空树的情况if(e==search(e)->data) return _root;//元素已存在无需插入++_size; BinNodePosi* t=_root;//创建新节点if(_root->data<e){//插入e时,以roo为分界线包含root,左边部分t变为e的左孩子,右边部分变为e的右孩子t->parent=_root=BinNode<T>(e,null,t,t->rChild);//构造e节点,左右孩子为t,t->rChildif(t->rChild) {t->rChild->parent=_root;t->rChild=null;}//将t的rChild的parent由t改为_root,自身连接位置改为null,防止野指针}else{t->parent=_root=new BinNode<T>(e,null,t->lChild,t);if(t->lChild) {t->lChild->parent=_root;t->lChild=null;}//原理同上}updateHeight(t);//更新祖先高度return _root;//无论e是否在原树中,返回值_root->data总是等于e
}

删除实现

原理与insert一致,当进行完search操作后,位于root位置的则是要删除的元素或者是相似的元素,在root的左子树内查找要删除元素的直接后继succ()(表示二叉树中序遍历序列列表)将其替代即可完成删除(这步操作与平衡搜索树的remove一致),保证树的局部性

template<typename T>bool Splay<T>::remove(const T& e){if(!_root||(e!=search(e)->data)) return false;//查找的节点信息未在树中BinNodePosi* w=_root;//要删除的节点已经伸展至树根位置if(!_root->lChild) {//若无左子树_root=_root->rChild; if(_root) _root->parent=null;}else if(!_root->rChild){//无右子树_root=_root->lChild; if(_root) _root->parent=null;}else{//左右子树都存在BinNodePosi* lTREE=_root->lChild;lTREE->parent=null;_root->lChild=null;//将左子树暂时切除_root=_root->rChild;_root->parent=null;search(w->data);//该查找必定失败,但是也将右子树中的最小节点伸展至root的位置//该过程也可调用直接后继,根据中序遍历在右子树中查找最小节点_root->lChild=lTREE;lTREE->parent=_root;//将左子树重新归位}delete w;_size--;//释放要删除的节点if(_root) updateHeight(_root);//树非空时,更新高度return true;
}

总结:伸展树复杂度与AVL树一致O(logn),局部性较强,平均效率较高, 但是针对最坏情况下的单次操作时任需要O(n), 不适用于对效率敏感的场所

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

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

相关文章

python的if和else、for、while语法_python-变量、if else语句 、for循环、while循环(4月26号)...

变量&#xff1a;五&#xff0e;注意&#xff1a;python是可执行程序 在linux写python第一行必须写#!/usr/bin/env python(声明解释器在windows中写python第一行需要写# -*- coding:utf-8 -*-Pycharm:开发调试效率高 在pycharm中new project 并且每天创建一个目录右键diectory…

c语言 库打印函数

函数#include<stdio.h>int printf(const char *format, ... );/* [until c99]写结果到stdout */int printf(const char *restrict format, ... );/* [since c99] */int fprintf(FILE *stream, const char *format, ... );/* [until c99]写结果到文件流stream */int fprin…

xhprof windows下安装和使用(转载)

1、使用5.3.3以上的php版本&#xff0c;或者直接下载wamp2.1集成环境。 2、下载xhprof for windows版本&#xff0c;地址&#xff1a;http://www.benjamin-carl.de/?downloadXHProf-0.10.0-PHP-5.3.3-VC6-x86-TS&#xff0c;把解压后的dll文件放到php的ext目录里面。 关于这个…

B树学习总结

B树 多路搜索树 当数据规模足够大的时候, 大部分数据存储到外存中, 常规的平衡二叉搜索树将无法满足需求理由如下: 常规二叉平衡搜索树每当进行search(),insert(),remove()操作的时候就会进行节点的切换,从而导致大量的IO操作,就此提出了多路搜索,尝试将原本的多个节点合在一…

嵌入式未来趋势是什么?

感谢CSDN编辑邀请 前几天通过了CSDN博客专家的申请&#xff0c;在CSDN博客摸爬滚打多少个日日夜夜后终于修成正果了&#xff0c;当时通过CSDN博客专家时赶紧把消息发给了以前的创新基地同学&#xff0c;想起来&#xff0c;我们那时候刚开始学习单片机&#xff0c;就是从CSDN上面…

python如何调用阿里云接口_Python调用aliyun API设置阿里云负载均衡虚拟服务器组权重...

环境准备系统环境CentOS Linux release 7.2.1511 (Core)[rootlocalhost ~]# cat /proc/versionLinux version 3.10.0-327.el7.x86_64 (builderkbuilder.dev.centos.org) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Thu Nov 19 22:10:57 UTC 2015[rootlocal…

js动态添加删除节点

转载于:https://www.cnblogs.com/jiaobaobao/p/6762692.html

C++与Java中的static成员总结

简述 在结构化程序设计中,内存中数据的共享是通过参数, 全局变量实现的; 在面向对象程序设计中函数与数据成员封装在一起, 数据共享通过类内部数据成员之间的相互访问, 外部对象则通过静态成员(即static成员)来共享数据; 接下来通过面向对象叙述static特性 C中的static 静…

书中自有黄金屋~外加中奖结果通知

人生的路很长&#xff0c;很艰辛&#xff0c;只有不断学习才能超越梦想&#xff0c;大牛是如何成长的&#xff01;首先要多看多听多写~~今天推荐一些大牛们都关注的技术公众号&#xff0c;机器学习、架构、前端、嵌入式、PY学习.....希望能够帮助到大家&#xff0c;引领我们前行…

python迭代算法_Python实现简单的梯度下降法

Python 实现简单的梯度下降法机器学习算法常常可以归结为求解一个最优化问题&#xff0c;而梯度下降法就是求解最优化问题的一个方法。梯度下降法(gradient descent)或最速下降法(steepest decent)&#xff0c;是求解无约束最优化问题的一种最常用的方法。梯度下降法实现简单&a…

[Linux]Linux应用程序中添加强制中断处理

注册CtrlC的按键signal信号捕捉&#xff0c;在捕捉到该动作后&#xff0c;强制退出应用程序 void handle_sig(int num) {printf( "%s\n", __func__ );exit(1); }int main( int argc, char **argv ) {signal(SIGINT, handle_sig); //....................... } 转载于…

顺序表的应用__电话本

顺序表的建立及使用 顺序表: 就所谓的数组式操作 编程实现顺序存储结构中的基本操作的实现&#xff08;电话本的建立、插入、删除、修改、逆置、查找、输出&#xff09; 整个操作过于简陋, 只对上述功能做叙述, 采用结构体数组实现, 本打算用class操作, 可因为某种原因就搁置…

拨号云服务器怎么自动配置网关_云服务器配置网站卡慢怎么办

网站访问卡慢有很多原因&#xff0c;一次完整的 HTTP 请求包括域名解析、建立 TCP 连接、发起请求、云服务器接收到请求进行处理并返回处理结果、浏览器对 HTML 代码进行解析并请求其他资源&#xff0c;以及对页面进行渲染呈现。其中&#xff0c;HTTP 的请求过程经历了用户本地…

TVS 和压敏电阻联合使用进行浪涌保护时,压敏电阻的压敏电压要低于TVS 的钳位电压 VC。

TVS(瞬态电压抑制器)二极管和MOV(金属氧化物压敏电阻)通常被用于电路中以提供浪涌保护。当两者联合使用时,设计要求MOV的压敏电压低于TVS二极管的钳位电压VC是因为: 1、分担能量: MOV设计用于吸收和分散大量能量,能够在遭受浪涌时承受较长时间的高电压。MOV在其压敏电压…

通俗理解Java中的Lambda表达式

Lambda Lambda表达式支持将代码块作为方法参数, 允许使用更为简洁的方式实现抽象类或接口的抽象方法, 而不再是通过匿名内部类的方式, 它具有对某一方法重写或实现的功能; 接下来通过一个简单的例子了解一下 public class LambaExpressionDemo {public void eat(Eatable e) {…

中断下半部机制-softirq-Tasklet-工作队列

中断上半部和下半部 在中断上半部,就是中断处理函数里面,是关中断的,所以为了快速执行,不能放太多的处理代码,只能执行非常短,这就衍生出了中断下半部。下半部主要是为了方便执行大量和本次中断相关的代码。 中断下半部的三种机制 下半部上下文顺序执行保障softirq中断…

jquery源码中noConflict(防止$和jQuery的命名冲突)的实现原理

jquery源码中noConflict(防止$和jQuery的命名冲突)的实现原理 最近在看jquery源码分析的视频教学&#xff0c;希望将视频中学到的知识用博客记录下来&#xff0c;更希望对有同样对jquery源码有困惑的童鞋能有一点点的帮助&#xff08;我是从一个小白的角度出发&#xff0c;感觉…

手机java软件_浅谈软件开发就业前景

​  我国信息化人才培养还处于发展阶段&#xff0c;导致社会实际需求人才基数远远大于信息化人才的培养基数&#xff0c;使得数以万计的中小企业急需全面系统掌握软件开发基础技能与知识的软件工程师。目前对软件已达20万并且以每年20%左右的速度增长。在未来5年内合格软件人…

单链表的应用(电话本)

单链表 单链表的定义就不说了, 很简单, 请自行百度; 那么从今天的主题<单链表的应用>入手; 利用单链表实现电话本的模拟程序&#xff1a;定义单链表的数据类型&#xff0c;将头插法和尾插法、插入、逆置、删除、查找、修改、计数、输出等操作都定义成子函数的形式&#…

有意思的BAT CMD if while循环 整型自增

引言 我们开发过程中经常遇到写bat进行测试的&#xff0c;需要对这方面有些基础&#xff0c;我给出个示例&#xff0c;也方便自己以后工作做参考。 echo off title qifa :looprem setlocal enabledelayedexpansionset /a a1 echo loop %a%choice /t 1 /d y /n >nulrem 判断…