当前位置: 首页 > wzjs >正文

网站模板套用湖南岚鸿cms智能云平台

网站模板套用湖南岚鸿,cms智能云平台,网站开发工作招聘,wordpress 密码忘记了本节重点 理解AVL树的概念掌握AVL树正确的插入方法利用_parent指针正确更新平衡因子掌握并理解四种旋转方式:左单旋,右单旋,左右双旋,右左双旋 一、AVL树的概念 AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis&…

本节重点

  • 理解AVL树的概念
  • 掌握AVL树正确的插入方法
  • 利用_parent指针正确更新平衡因子
  • 掌握并理解四种旋转方式:左单旋,右单旋,左右双旋,右左双旋

一、AVL树的概念

AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。

AVL树最先发明自平衡二叉搜索树,AVL是一颗空树,或者具备下列性质的二叉搜索树:它的左右子树都是AVL树,且左右子树的高度差的绝对值不超过1。AVL树是一颗高度平衡搜索二叉树,通过控制高度差去控制平衡。

AVL树的实现引入一个平衡因子的概念(balance factor)的概念,每个节点都有一个平衡因子,任何节点的平衡因子等于右子树高度减去左子树高度,也就是说任何节点的平衡因子等于0/1/-1,AVL树并不是必须要平衡因子,但是有了平衡因子可以更方便我们去进行观察和控制树是否平衡,就像一个风向标一样。

AVL树整体的节点数量和分布和完全二叉树类似,但是AVL树高度可以控制在logN,所以增删查改的效率也可以控制在O(logN),相比二叉搜索树有了本质的提升。

如图,每个节点上方的小数字表示该节点的平衡因子,平衡因子只能为-1/1/0当为2/-2时我们要通过旋转将左右子树重新达到平衡状态。 

二、AVL树的实现

2.1 AVL树的结构

AVL树我们分成两部分来实现,一部分是单个节点的定义,一部分是AVL树。并且用两个类进行封装:

template<class K>
struct AVLTNode//AVL树节点的定义
{K _key;struct AVLTNode<K>* _left;struct AVLTNode<K>* _right;struct AVLTNode<K>* _parent;//引入parent方便我们快速向上更新平衡因子int _bf;//平衡因子(balance factor)//构造函数:AVLTNode(K key):_key(key), _left(nullptr), _right(nullptr), _parent(nullptr),_bf(0){}
};//AVL树的定义
template<class K>
class AVLTree
{typedef struct AVLTNode<K> Node;
public:
private:Node* root = nullptr;
};

2.2 AVL树的插入

AVL树插入的步骤:

  1. 插入一个值按照二叉搜索树的规则插入
  2. 新增节点后,只会影响祖先节点的高度,也就是可能会影响部分祖先节点的平衡因子,所以更新从新增节点->根节点路径上的平衡因子,实际最坏情况下更新到根,有些情况更新到中间就停止了。
  3. 更新平衡因子过程中没有出现问题,则插入结束
  4. 更新平衡因子的过程中出现不平衡,对不平衡子树旋转,旋转后降低了子树的高度,不会再影响上一层,所以插入结束

2.2.1 先按照搜索二叉树规则插入

在插入之前,我们需要判断该AVL树是否为空,若为空直接在_root 新增节点并返回,若不为空说明AVL树中已经存在节点,这时我们需要从根节点开始依次按照搜索树的规则寻找插入位置,找到之后创建新节点并链入到AVL树中。

代码示例:

bool Insert(const K& key){if (_root == nullptr){//AVL是一颗空树_root=new Node(key)return 1;}else{Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{assert(false);}}//链接新节点:cur = new Node(key);if (cur->_key > parent->_key){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;}

2.2.2 判断并更新平衡因子

更新规则:

平衡因子=右子树高度-左子树高度

插入节点会增加子树高度,影响当前节点平衡因子因为一次只能插入一个节点所以平衡因子要么++要么--:

插入在右子树平衡因子++;插入在左子树平衡因子--。

平衡因子的三种情况:(0,-1/1,-2/2)

1、更新后parent节点平衡因子为0

说明更新之前parent节点平衡因子为1或-1也就是左右子树一边高一边低,节点插入在低的一边,插入后左右平衡不会影响上一级节点的平衡因子。

2、更新后parent节点平衡因子为1/-1

说明更新之前parent节点平衡因子为0,插入后左右子树一边高一边低会影响上一级节点的平衡因子,所以要继续向上更新。

3、更新后parent节点平衡因子为2/-2

说明更新之前parent节点平衡因子为1/-1也就是左右子树一边高一边低,节点插入在高的一边

代码示例: 

while (parent)
{if (parent->_right == cur){parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0){//说明新增节点在低的一边,插入后左右子树平衡//不会影响祖先节点的 _bf直接breakbreak;}else if(parent->_bf==1||parent->_bf==-1){//新增节点之后为1或-1说明之前为0(左右子树平衡)//此时需要更新依次更新祖先节点的 _bf直到更新到根节点或某一祖先节点_bf==0cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == 2 && cur->_bf == 1){//单纯右边高,左旋RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == -1){//单纯左边高,右旋RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){//先左后右,右左双旋RotateRL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){//先右后左,左右双旋RotateLR(parent);}else{assert(false);}break;}else{assert(false);}
}

2.2.3 (不平衡)旋转子树

旋转的原则:

  • 保持搜索树的规则
  • 让旋转的树从不满足变为平衡,其次降低树的高度

首先我们需要明白的是旋转操作分为两部分,一是调整节点之间的链接关系,二是更新平衡因子     _bf

左单旋(RotateL)

当parent的平衡因子为2,且cur的平衡因子为1时AVL树会呈现右子树一边高的形式,这时我们需要进行左旋操作,需要注意的是满足 parent->_bf==2 && cur->_bf==1 条件的AVL树的形式可能有多种:

为了便于理解,我们可以选择一种简单的情况进行分析并写出相应代码:

代码示例:

void RotateL(Node* parent){Node* SubR = parent->_right;Node* SubRL = SubR->_left;Node* pparent = parent->_parent;if (SubRL){SubRL->_parent = parent;}parent->_right = SubRL;SubR->_left = parent;parent->_parent = SubR;if (parent == _root){_root = SubR;SubR->_parent = nullptr;}else{if (pparent->_right == parent){pparent->_right = SubR;}else{pparent->_left = SubR;}SubR->_parent = pparent;}//节点链接关系调整完成后更新平衡因子:SubR->_bf = 0;parent->_bf = 0;}
右单旋(RotateR)

类似的是,满足 parent->_bf==-2 && cur->_bf==-1 条件的AVL树的形式也可能有多种

我们也选择其中一种简单的情况进行分析和编写代码:

void RotateR(Node* parent){Node* SubL = parent->_left;Node* SubLR = SubL->_right;Node* pparent = parent->_parent;if (SubLR){SubLR->_parent = parent;}parent->_left = SubLR;SubL->_right = parent;parent->_parent = SubL;if (parent == _root){_root = SubL;SubL->_parent = nullptr;}else{if (pparent->_right == parent){pparent->_right = SubL;}else{pparent->_left = SubL;}SubR->_parent = pparent;}//节点链接关系调整完成后更新平衡因子:SubL->_bf = 0;parent->_bf = 0;}
左右双旋(RotateLR)

与单旋不同的是,双旋对应的AVL树的结构不再是单纯一边高,我们由条件判断很容易就可以看出来(parent->_bf == -2 && cur->_bf == 1 或 parent->_bf == 2 && cur->_bf == -1),此时我们发现AVL树节点类似“折线形”排列,这时单纯的单旋无法使二叉树再次平衡,我们需要进行两次单旋来解决。

类似的是满足双旋触发条件时,AVL树的结构要是拓展开来也有非常多种情况,我们可以选择其中一种较为简单的情况来分析并编写相应代码:

需要注意的是左右双旋的时候对SubLR的_bf也要进行考虑,目的是确定SubLR是否存在单个的子树,因为最终SubLR的子树会链入SubL或者parent影响两个节点的平衡因子

void RotateLR(Node* parent){Node* SubL = parent->_left;Node* SubLR = SubL->_right;int bf = SubLR->_bf;RotateL(parent->_left);RotateR(parent);if (bf == 1){SubLR->_bf = 0;parent->_bf = 0;SubL->_bf = -1;}else if (bf == 0){parent->_bf = 0;SubLR->_bf = 0;SubL->_bf = 0;}else{SubLR->_bf = 0;parent->_bf = 1;SubL->_bf = 0;}}
右左双旋(RotateRL)

 

void RotateRL(Node* parent){Node* SubR = parent->_right;Node* SubRL = SubR->_left;int bf = SubRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 1){SubRL->_bf = 0;parent->_bf = -1;SubR->_bf = 0;}else if (bf == 0){parent->_bf = 0;SubLR->_bf = 0;SubL->_bf = 0;}else{SubRL->_bf = 0;parent->_bf = 0;SubR->_bf = 1;}}


文章转载自:

http://Nhko32vR.msbpb.cn
http://uvpbguOB.msbpb.cn
http://uIrflQex.msbpb.cn
http://leqauc7d.msbpb.cn
http://CvPodl2d.msbpb.cn
http://VQeusgER.msbpb.cn
http://AqCOVBUA.msbpb.cn
http://gAghKSmf.msbpb.cn
http://2XdCIyKU.msbpb.cn
http://dFftGbgr.msbpb.cn
http://de9AAr8s.msbpb.cn
http://EtwSU9ib.msbpb.cn
http://2YC3N2sv.msbpb.cn
http://ZDSySSad.msbpb.cn
http://ZwyvDNQM.msbpb.cn
http://NBMMd7hj.msbpb.cn
http://UzeDCx3L.msbpb.cn
http://5LArKPjc.msbpb.cn
http://7bNRJj7Z.msbpb.cn
http://MrugdVkE.msbpb.cn
http://mPUpoFHW.msbpb.cn
http://wqRi07Em.msbpb.cn
http://EMu45wbH.msbpb.cn
http://tzBTIXWp.msbpb.cn
http://L3EocYD9.msbpb.cn
http://58X4HGiq.msbpb.cn
http://wOr1WjkU.msbpb.cn
http://0YjGmr7E.msbpb.cn
http://GZpae9DV.msbpb.cn
http://EtXiX76F.msbpb.cn
http://www.dtcms.com/wzjs/768890.html

相关文章:

  • 黑龙江省住房和建设厅网站wordpress怎么选择中文版
  • php怎样做网站最近军事动态
  • 网站建设维护要求google search
  • 无锡网站制作哪里实惠炉石做任务抽奖网站
  • 查外链网站wordpress点击弹窗
  • 网站开发 验收模板可以在哪些网站 app做推广的
  • 西安做网站朋朋谁知道苏州溪城水处理网站谁做的
  • 成都高端模板建站网站策划过程
  • 西安品牌网站建设网页版qq登录入口版qq账号登录界面
  • com网站域名注册php做网站软件
  • 软件开发网站有哪些问题饰品公司网站建设策划书
  • 哪个网站做h5号黄骅港务集团有限公司
  • 网站策划案不花钱的做网站
  • soho的网站怎么做wordpress分享 赞插件
  • 塑料公司网站建设方案化妆品网站建设实施背景
  • 响应式网站设计的规范自己做网络棋牌网站流程
  • 成都网站建设新线加网站建设培训四川
  • 网站公告弹窗源码在线手机建网站
  • 销售牛的网站广州网络推广公司有哪些
  • 潍坊企业网站郑州网站优化哪家专业
  • 怎样管理一个俄语网站网站 系统 区别
  • 怎么查网站的注册信息21世纪上海人才网官网
  • 绵阳市建设工程监督网站嘉祥网站建设哪家便宜
  • 广东建设监理协会网站个人账号十大网站建立公司
  • 四平市城乡建设局网站悟空建站是什么
  • 取消网站的通知书网站开发项目流程设计
  • 怎样查看网站是否被百度收录[8dvd]flash网站源文件 flash整站源码
  • 保定网站设计制作需要多少钱怎么做线上销售
  • 重庆云阳网站建设wordpress查询分页插件
  • 做网站的公司叫什么名字好跨境电商怎么做视频教程