AVL树学习总结

AVL树

平衡二叉树的缺点
由于平衡二叉搜索树的search(), insert(),remove()接口的运行时间与二叉树的高度成正比,所以若不能有效控制树高, 从平均复杂度来看,二叉平衡搜索树并不能让人满意

理想平衡
二叉树的性能取决于树的高度,只有当左右子树的高度接近时才能达到理想平衡, 高度为o(logn); 就比如完全二叉树与满二叉树

AVL树
由于从平常状态转变为理想状态下,所耗费的资源较多, 所以就设定适度的平衡标准, 就此提出AVL树, AVL树可保证树的高度始终保持在O(logn)内
AVL树的平衡标准: 任一节点都具有平衡因子(其值balFac(v)= height(lc(v)) - height(rc(v)) )的绝对值不能超过1
AVL继承平衡二叉搜索树, 对search(), insert(), remove()接口进行重写

//以下宏定义用于简化节点的平衡性判断
//stature表示当前节点的高度
#define Balanced(x)(stature((x).lChild) == stature((x).rChild)))//理想状态
#define BalFac(x)(stature((x).lChild) - stature((x).rChild))//平衡因子
#define AVBalanced(x) ((-2<BalFac(x)) && (BalFac(x)<2 ))//AVL树条件

注:空树的高度取-1, 单节点子树高度取0
例: 如图所示节点的平衡因子(皆为左子树高度-右子树高度)
这里写图片描述
节点的插入以及删除都将影响节点的平衡度

重平衡
在插入x后, AVL失衡, 可沿x出发向上寻找首次出现失衡的节点, 将其确定为祖父节点(g(x)),然后根据g(x),找到g(x)的儿子节点, 孙子节点, 将其设置为p,v, 由于原树为平衡的,所以在整个向上查找g的过程只需O(logn)的时间 ; 针对g, p, v三个节点的位置进行zig(顺时针旋转节点,使后代上升为父节点), zag(逆时针)旋转,用于重平衡

//将确定p, v的过程写为宏定义;
//根据插入过程不平衡的出现可得查找原则:左右孩子取高度更高的为p,左右孩子等高,取父亲同侧,v同上
//根据上图可知2为g,p为-1,v为1
#define tallerChild(x) ( stature((x)->lChild)>stature((x)->rChild))?(x)->lChild:( (stature((x)->rChild)>stature((x)->lChild))?(x)->rChild:((x->parent->lChild)?x->lChild:x->rChild)))
//每一层的比较对应着查找p,v

单旋: 只执行zig/zag旋转,且执行一次
双旋: 旋转过程中即包含zig又包含zag

//zig简述
g(x)->lChild=p->rChild;
p->Child->parent=g(x);//将孩子节点旋转
p->parent=g(x)->parent;
g(x)->parent=p;//将父节点旋转
//zag原理同上

插入过程中的重平衡
当节点x插入后, 可能导致二叉树结构一系列节点发生不平衡现象(也就是重心偏向一边), 但是经过局部旋转后将可能导致一系列的恢复平衡

删除过程中的重平衡
当节点x删除后, 只会导致局部的节点发生不平衡现象, 当对局部的不平衡进行zig/zag调整时, 局部子树的高度将有可能降低,又有可能导致上一层的祖先发生不平衡,因此需要不断向上遍历,发现一个失衡的祖先则将其旋转至平衡状态,直到更新到没有出现不平衡现象

统一重平衡算法
在删除与插入的过程中都涉及到zig,zag旋转,于是可将插入,删除操作统一,为避免通过zig,zag旋转出现的繁琐,于是提出了3+4重构的方式
3+4重构: 直接传入g,p,v三个节点以及这三个节点对应的左右子树,对其进行全部重新连接,由此可覆盖所有的旋转操作

template<typename T>BinNodePosi* BST<T>::connect34(BinNodePosi* a,BinNodePosi* b,BinNodePosi* c, BinNodePosi* T0,BinNodePosi* T1,BinNodePosi* T2,BinNodePosi* T3){a->lChild=T0; if(T0) T0->parent=a;a->rChild=T1; if(T1) T1->parent=a;updateHeight(c);//更新数的高度c->lChild=T2; if(T2) T2->parent=c;c->rChild=T3; if(T3) T3->parent=c;updateHeight(c);//更新数的高度b->lChild=a; if(T0) a->parent=b;b->rChild=c; if(T2) c->parent=b;updateHeight(c);//更新数的高度return b;//对传入的节点进行重连操作
}
//针对zig,zag旋转模式,传入不同的参数调用connect34
template<typename T>BinNodePosi* BST<T>::rotateAt(BinNodePosi* v){BinNodePosi* p=v->parent,g=p->parent;if(g->lChild==p)//p为左孩子,zig旋转if(p->lChild==v){//v为左孩子,执行zig,zigp->parent=g->parent;//向上连接return connect34(v,p,g,v->lChild,v->rChild,p->rChild,g->rChild);}else{//zig,zag双旋v->parent=g->parent;return connect34(p,v,g,p->lChild,v->lChild,v->rChild,g->rChild);}else //zag旋转if(p->rChild==v){//zag,zagp->parent=g->parent;//向上连接return connect34(g,p,v,g->lChild,p->lChild,v->lChild,v->rChild);}else{//zag,zig旋转v->parent=g->parent;return connect34(g,v,p,g->lChild,v->lChild,v->rChild,p-rChild);}}

insert实现

//将关键码e插入合适的位置,然后调整平衡树状态,使其平衡
template<typename T>BinNodePosi* AVL<T>::insert(const T& e){BinNodePosi* x=search(e);if(x) return x;//节点e已存在树中x=new BinNode<T>(e,_hot);_size++;//_hot查找过程中指向e应该存在的位置,插入过程将导致某一祖先出现不平衡for(BinNodePosi* g=_hot;g;g=g->parent){//从x的位置向上查找检查每个祖先,直到出现不平衡的祖先if(!AVlBalanced(*g)){//发现失衡的祖先调用3+4重构使之平衡FromParentTo(*g)=rotateAt(tallerChild(tallerChild))//tallerChild查找p,v的位置break;          }elseupdateHeight(g);//向上查找顺便更新当前g的高度}return x;//返回更新后的结果
}

remove的实现
search查找出要删除的节点位置,调用remove(),查找失衡的局部子树, 调用3+4重构使其恢复平衡,remove的实现与insert差不多, 区别只是在于,remove相比insert多调用一次remove函数

注:经过上述操作后, insert,remove复杂度将降低到O(logn)的状态

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

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

相关文章

nginx编译安装_Nginx编译安装nginx-upsync-module模块以实现动态负载

安装依赖包OpenSSL在官网下载页下到最新稳定版1.0.2q。PCRE在 PCRE 官网可以找到下载地址&#xff0c;这里选择8.x的最高版本 pcre-8.42.tar.gz。zlibzlib 直接选择官网首页最新的zlib-1.2.11.tar.gz。下载nginx 源码包及nginx-upsync-module模块源码这里下载的是nginx稳定版ng…

centos7 qt之程序编译 cant start process “cmake”

之所以出现这个问题&#xff0c;是由于qt内置的cmake与系统已安装的cmake命令冲突。解决的方法是&#xff0c;在build里将cmake命令加上绝对路径。 问题得以解决。转载于:https://www.cnblogs.com/jiu0821/p/6762343.html

码农笑话图片十张

原创翻译~转载请说明出处~~~~~~~~1、如果你让码农给你做个事情&#xff0c;比如修个灯泡&#xff0c;他会这样去执行你的指令2、分享一个码农发现并解决bug的过程&#xff0c;实在是符合我们码农的人设3、码农的一天&#xff0c;像极了我的一天4、至今为止&#xff0c;没有遇到…

伸展树学习总结

伸展树 与AVL树类似, 伸展树也是二叉搜索树的一种形式, 伸展树无需保证时刻保持全树的平衡,也不需要像AVL树一样要求记录平衡因子的附加信息 伸展树的提出源于信息访问的局部性(刚被访问过的信息有可能再次被访问,要被访问的元素可能位于刚访问过的元素的附近), 就伸展树而言…

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中断…