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

怎么用微信做网站常德网站优化公司

怎么用微信做网站,常德网站优化公司,软装设计理念,h5制作开发新报价图片简介 AVL树是最先被发明出来的自平衡二叉查找树,在1962由前苏联科学家G. M. Adelson-Velsky和E. M. Landis在论文中发表。AVL树中引入了平衡因子,每一个节点都有一个平衡因子(一般是右子树高度 - 左子树高度);AVL树要…

简介

AVL树是最先被发明出来的自平衡二叉查找树,在1962由前苏联科学家G. M. Adelson-Velsky和E. M. Landis在论文中发表。AVL树中引入了平衡因子,每一个节点都有一个平衡因子(一般是右子树高度 - 左子树高度);AVL树要求左右子树高度相差不能超过1,即平衡因子只能是0,1或-1。AVL树的高度始终是log(n),n为节点数量。

AVL树的结构

template<class K,class V>
struct AVLTreeNode   //定义节点的结构
{pair<K, V> _kv;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf;//平衡因子balance factorAVLTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _bf(0){}
};template<class K,class V>
class AVLTree
{typdef AVLTreeNode<K, V> Node;
public:private:Node* _root = nullptr;};

_kv是AVL树储存的键值对,既能存储键值key,每一个key也能对应储存一个value值。

为什么要有_parent?

AVL树通过平衡因子来控制树的平衡,插入或删除数据后,需要回溯到父节点计算平衡因子,所以我们需要_parent来储存每一个节点父节点的值。

AVL树的插入 

插入的基本流程

寻找插入的位置

按照二叉树遍历的顺序找到要插入的位置。

更新平衡因子

插入一个新的节点之后,如果父节点的平衡因子发生改变,则需更新从根节点到父节点这条路径的所有节点的平衡因子。

判断是否产生不平衡

如果更新平衡因子之后,没有出现平衡因子不为0,-1,1的,则说明树是平衡的,插入结束。

如果出现了不平衡,对不平衡⼦树旋转,旋转后本质调平衡的同时,本质降低了⼦树的⾼度,不会再影响上⼀层,所以插⼊结束。

平衡因子的更新

更新的原则

平衡因⼦ = 右⼦树⾼度-左⼦树⾼度。
只有⼦树⾼度变化才会影响当前结点平衡因⼦。
插⼊结点,会增加⾼度,所以新增结点在parent的右⼦树,parent的平衡因⼦++,新增结点在
parent的左⼦树,parent平衡因⼦--。
parent所在⼦树的⾼度是否变化决定了是否会继续往上更新。

更新停止的条件

更新后parent的平衡因⼦等于0,更新中parent的平衡因⼦变化为-1->0 或者 1->0,说明更新前
parent⼦树⼀边⾼⼀边低,新增的结点插⼊在低的那边,插⼊后parent所在的⼦树⾼度不变,不会
影响parent的⽗亲结点的平衡因⼦,更新结束。
更新后parent的平衡因⼦等于1 或 -1,更新前更新中parent的平衡因⼦变化为0->1 或者 0->-1,说
明更新前parent⼦树两边⼀样⾼,新增的插⼊结点后,parent所在的⼦树⼀边⾼⼀边低,parent所
在的⼦树符合平衡要求,但是⾼度增加了1,会影响parent的⽗亲结点的平衡因⼦,所以要继续向
上更新。
更新后parent的平衡因⼦等于2 或 -2,更新前更新中parent的平衡因⼦变化为1->2 或者 -1->-2,说
明更新前parent⼦树⼀边⾼⼀边低,新增的插⼊结点在⾼的那边,parent所在的⼦树⾼的那边更⾼
了,破坏了平衡,parent所在的⼦树不符合平衡要求,需要旋转处理,旋转的⽬标有两个:1、把
parent⼦树旋转平衡。2、降低parent⼦树的⾼度,恢复到插⼊结点以前的⾼度。所以旋转后也不
需要继续往上更新,插⼊结束。
不断更新,更新到根,跟的平衡因⼦是1或-1也停⽌了。

插入的整体框架:
 

bool insert(pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;//不应许插入相同的值}}cur = new Node(kv);if (cur->_kv.first < parent->_kv.first){parent->_left = cur;}else if (cur->_kv.first > parent->_kv.first){parent->_right = cur;}cur->_parent = parent;//更新平衡因子while (parent){// 更新平衡因⼦if (cur == parent->_left)parent->_bf--;elseparent->_bf++;if (parent->_bf == 0){// 更新结束break;}else if (parent->_bf == 1 || parent->_bf == -1){// 继续往上更新cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){// 不平衡了,旋转处理break;}else{assert(false);}}return true;}

旋转

旋转的原则

1.保持搜索树的规则

2.让树变平衡,降低旋转树的高度

根据插入的位置不同,旋转一共分为四种,左单旋/右单旋/左右双旋/右左双旋

右单旋

右单旋适合处理下图这种情况,插入前,左子树高度刚好比右子树高1,且刚好插入值为在左子树最左边(比原来树中的所有值都小)。

普遍情况:

为了方便理解我们这里取特例: 

插入节点-3之后,树不再平衡。这时候就需要通过旋转来使树再次平衡。怎样让树再次平衡呢?

我们只需要操作最深的那一条路径就好了,让它高度减一,在移到右子树上,这样平衡因子就为0了。

虽然不符合AVL树的规则了,但是这颗树还是符合二叉搜索树的规则的。还是可以中序遍历。

这棵树中序遍历的结果是:-3,1,5,8,10,15。把10拿下来让左子树高度减一,再向办法把10放到右子树中,5的右子树绝对比它的父节点(10)小,所以可以把10变成5的右节点,同时让8接到10的左节点。这样即保证中序遍历的结果又使树恢复了平衡。

代码实现:

//右单旋void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;// 需要注意除了要修改孩⼦指针指向,还是修改⽗亲parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;// parent有可能是整棵树的根,也可能是局部的⼦树// 如果是整棵树的根,要修改_root// 如果是局部的指针要跟上⼀层链接if (parentParent == nullptr){_root = subL;subL->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}parent->_bf = subL->_bf = 0;}

要处理的三个节点

注意:parent不一定是根节点,所以要创建一个临时变量parentParent储存parent的父节点,处理好子树之后,再让subL的父节点指向parentParent(parentParent为空则,subL变为根节点)。

左单旋

左单旋适合一下情况

树中的左旋和右旋互为对称操作,左旋和右旋是可以相互抵消的,即经历一次左旋和一次右旋之后会恢复成原树。

 代码实现:

void RoateL(Node* parent){Node* subR = parent->_right;parent->_right = subR;Node* subRL = subR->_left;if (subRL){subRL->_parent = subR;}Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;parent->_right = subRL;if (subRL){subRL->_parent = parent;}if (parentParent){subR->_parent = parentParent;if (parentParent->_left == parent){subR->_parent = parentParent;parentParent->_left = subR;}else if(parentParent->_right == parent){subR->_parent = parentParent;parentParent->_right = subR;}}else if (parentParent == nullptr){_root = subR;}parent->_bf = subL->_bf = 0;}

左右双旋

观察下面这种情况,它并不是纯粹的左边高,对于节点10是左边高,对于节点5来说是右边高。

这时候单纯的右单旋或者左单旋都不能解决问题, 这时候两次单旋就可以解决问题。以节点5为旋转点,进行一次左单旋,这时候就是一个完全左边高的树结构,完全符合右单旋的应用场景,以节点10为旋转点进行一次右单旋,树恢复平衡。

要处理的节点:

 

 代码实现:

void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);if (bf == 0){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 0;}else if (bf == -1){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 1;}else if (bf == 1){subL->_bf = -1;subLR->_bf = 0;parent->_bf = 0;}else{assert(false);}}

右左双旋 


右左双旋于左右双旋类似,接下来我们以普适情况抽象出a,b,c三棵子树来讨论。另外我们需要把b⼦树的 细节进⼀步展开为12和左⼦树⾼度为h-1的e和f⼦树,因为我们要对b的⽗亲15为旋转点进⾏右单旋,右单旋需要动b树中的右⼦树。

b⼦树中新增结点的位置不同,平衡因⼦更新的细节也不同,通过观察12的平衡因⼦不同,这⾥我们要分三个场景讨论。
场景一: h >= 1时,新增结点插⼊在e⼦树,e⼦树⾼度从h-1变为h并不断更新12->15->10平衡因
⼦,引发旋转,其中12的平衡因⼦为-1,旋转后10和12平衡因⼦为0,15平衡因⼦为1。

 场景二:h >= 1时,新增结点插⼊在f⼦树,f⼦树⾼度从h-1变为h并不断更新12->15->10平衡因⼦, 引发旋转,其中12的平衡因⼦为1,旋转后15和12平衡因⼦为0,10平衡因⼦为-1。

场景三:h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新15->10平衡因⼦,引发旋 转,其中12的平衡因⼦为0,旋转后10和12和15平衡因⼦均为0。

 

代码实现:

void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){subR->_bf = 0;subRL->_bf = 0;parent->_bf = 0;}else if (bf == 1){subR->_bf = 0;subRL->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;subRL->_bf = 0;parent->_bf = 0;}else{assert(false);}}

 查找

按照遍历二叉树的逻辑查找即可。

Node* Find(const K& key)//按照键值查找{Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{return cur;}}return nullptr;}

AVL树平衡检测

对于实现的AVL树是否合格,我们通过判断左右子树高度差来判断,即判断平衡因子。

int _Height(Node* root){if (root == nullptr)return 0;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}bool _IsBalanceTree(Node* root){// 空树也是AVL树if (nullptr == root)return true;// 计算pRoot结点的平衡因⼦:即pRoot左右⼦树的⾼度差int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);int diff = rightHeight - leftHeight;// 如果计算出的平衡因⼦与pRoot的平衡因⼦不相等,或者// pRoot平衡因⼦的绝对值超过1,则⼀定不是AVL树if (abs(diff) >= 2){cout << root->_kv.first << "⾼度差异常" << endl;return false;}if (root->_bf != diff){cout << root->_kv.first << "平衡因⼦异常" << endl;return false;}// pRoot的左和右如果都是AVL树,则该树⼀定是AVL树return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);}

http://www.dtcms.com/wzjs/442774.html

相关文章:

  • 秦皇岛网站建设公司营销软文模板
  • 做网站有没有受骗过今日头条普通版
  • 龙岗 网站建设公司网址怎么注册
  • 中国卫生人才网石家庄seo外包的公司
  • piwigo wordpressseo网络营销推广
  • 网站的提示公告做滚动字幕深圳网络推广建站
  • 网站建设报价百度站长工具app
  • 湖州网站网站建设足球比赛直播2021欧冠决赛
  • 网站的轮播图怎么做短视频营销案例
  • 合肥网站建设制作公司哪里有网站推广优化
  • 郑州网站建设微信小程序建站工具有哪些
  • 网站外链建设工作总结深圳龙岗区优化防控措施
  • 天津做网站建设哪里有学电脑培训班
  • 网站建设客源在哪里找百度极速版推广员怎么申请
  • 服务器安全模式怎么进天津seo代理商
  • 企业现在有必要做网站吗西安网站seo诊断
  • 怎么做手机版网站百度最新秒收录方法2021
  • 永久3e38cos无风险优化师培训
  • wordpress essential 整站优化多少钱
  • 娃哈哈网站建设策划书seo外包公司费用
  • 做茶叶网站简述seo
  • 西安未央区网站建设百度搜索网
  • 免费b站在线人数在哪看西安seo网站关键词优化
  • 个人备案后做淘客网站知名品牌营销策略
  • 宣传中心网站建设脚上起小水泡还很痒是什么原因
  • 小公司做网站赚钱杭州制作公司网站
  • 家装博览会seo搜索引擎优化薪酬
  • 宁波产城生态建设集团网站关键词优化的作用
  • 中山免费建站google搜索引擎入口网址
  • b站推广网站2024游戏搜索引擎站长平台