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

贵阳做网站多少钱热搜榜上2023年热门话题

贵阳做网站多少钱,热搜榜上2023年热门话题,怎么在网站做推广不要钱,农业农村部农田建设管理司网站🚀个人主页:小羊 🚀所属专栏:C 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 前言一、AVL树二、AVL树的实现2.1 平衡因子2.2 旋转处理2.2.1 左单旋:插入新节点后单纯的右边高2.2.2 …
头像
🚀个人主页:@小羊
🚀所属专栏:C++
很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述

目录

  • 前言
  • 一、AVL树
  • 二、AVL树的实现
    • 2.1 平衡因子
    • 2.2 旋转处理
      • 2.2.1 左单旋:插入新节点后单纯的右边高
      • 2.2.2 右单旋:插入新节点后单纯的左边高
      • 2.2.3 左右旋:插入新节点后不是单纯的左边高
      • 2.2.4 右左旋:插入新节点后不是单纯的右边高
    • 2.3 验证AVL树的平衡
  • 三、完整代码


前言

本文仅适合了解二叉搜索树,但不了解AVL树底层原理的同学阅读哦。

本篇文章不会带你从头到尾实现AVL树,但会带你深入理解AVL树是怎么实现平衡的,怎么通过旋转变换实现保持平衡,以及实现平衡过程中的细节应该怎么处理等。


一、AVL树

前面的文章中我们分析过二叉搜索树的性能,得到的结果是理想情况下二叉搜索树的时间复杂度为O(LogN),但在极端情况下(即树蜕化为单边树时),这些操作的时间复杂度会退化为O(n),即使情况不那么极端,效率也不是特别高。

为了防止二叉搜索树出现一边偏高的情况,就需要想办法让二叉搜索树尽量保持平衡,所以两位苏联数学家(或称为俄罗斯数学家)G.M. Adelson-Velsky和E.M. Landis就发明了AVL树,其任何节点的两个子树的高度最大差别为1。

AVL树是具有一下性质的二叉搜索树:

  • 其左右子树都是AVL树
  • 左右子树高度差不超过1

二、AVL树的实现

本篇文章将沿用之前文章中Key-Value模型的代码,不再从底层开始实现,主要介绍在插入新节点后如何保持二叉搜索树的平衡问题。

2.1 平衡因子

如何保证AVL树的左右子树高度差不超过1?在AVL树的每个节点中存一个平衡因子,本文我们定义平衡因子 = 此节点右子树的高度 - 左子树的高度

  • 插入在左子树,平衡因子 - -
  • 插入在右子树,平衡因子++

更新祖先节点的平衡因子时,我们首先需要找到祖先节点,因此每个节点中还需要增加一个指向父节点的指针。
按照我们的需求,其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;//平衡因子//构造AVLTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0){}
}

是否继续往上更新祖先节点的平衡因子,要看parent所在子树的高度是否发生变化。

插入新节点后其父节点的平衡因子有以下几种情况:

  1. parent的平衡因子 == 0
    parent的平衡因子更新前是 -1 / 1,新节点插入在矮的那边,高度不变,不再往上更新
  2. parent的平衡因子 == 1 / -1
    parent的平衡因子更新前是0,parent所在子树高度都变化了,需要往上更新
  3. parent的平衡因子 == 2 / -2
    parent的平衡因子更新前是 -1 / 1,插入新节点后树不再平衡,需要旋转处理
pcur = new Node(kv);
if (parent->_kv.first > kv.first)//判断新节点应该插入左还是右
{parent->_left = pcur;
}
else
{parent->_right = pcur;
}
pcur->_parent = parent;//与父节点链接关系while (parent)//有可能更新到根节点去
{parent->_bf = parent->_left == pcur ? parent->_bf - 1 : parent->_bf + 1;if (parent->_bf == 0)//插入前后高度不变{break;}else if (parent->_bf == 1 || parent->_bf == -1){//高度变了,继续往上更新pcur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){//插入节点后二叉树不平衡了,需要旋转处理}else{assert(false);//检测AVL树是否异常}
}

2.2 旋转处理

当二叉搜索树出现不平衡的情况时,需要旋转处理,对应插入后二叉搜索树的各种情况,主要有四种旋转的方式来保持平衡。

其中:

  • h代表子树的高度,可以是0、1、2…
  • 我们用能代表所有情况的四种类型的抽象图来研究旋转方式,单纯研究某几种情况没有意义

原则:

  1. 保持搜索树的性质
  2. 降低高度,控制平衡

2.2.1 左单旋:插入新节点后单纯的右边高

在这里插入图片描述

旋转处理过程中,我们主要关注三个节点(以上图为例):10(标记为parent)、30(标记为subR)、b(标记为subLR)。

在旋转过程中,有以下几种情况需要考虑:

  1. subR的左孩子可能存在,也可能不存在
  2. parent可能是根节点,也可能是子树。如果是根节点,旋转完成后,要更新根节点;如果是子树,可能是某个节点的左子树,也可能是右子树
//左单旋
void RotateL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;//subRL是有可能为空的parent->_right = subRL;subR->_left = parent;Node* parentparent = parent->_parent;parent->_parent = subR;if (parentparent == nullptr)//subR有可能变成根{_root = subR;}else{if (parentparent->_left == parent){parentparent->_left = subR;}else{parentparent->_right = subR;}}subR->_parent = parentparent;if (subRL){subRL->_parent = parent;}parent->_bf = subR->_bf = 0;//更新平衡因子
}

旋转处理过程中主要是处理各节点的父节点指针的指向和平衡因子的更新。


2.2.2 右单旋:插入新节点后单纯的左边高

在这里插入图片描述

其处理方式和左单旋相似,可参考左单旋。

//右单旋
void RotateR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;subL->_right = parent;Node* parentparent = parent->_parent;parent->_parent = subL;if (parentparent == nullptr){_root = subL;}else{if (parentparent->_left == parent){parentparent->_left = subL;}else{parentparent->_right = subL;}}subL->_parent = parentparent;if (subLR){subLR->_parent = parent;}subL->_bf = parent->_bf = 0;
}

2.2.3 左右旋:插入新节点后不是单纯的左边高

在这里插入图片描述

这种情况只用左旋或右旋只会原地打转,不能降低平衡。
我们需要先对subL进行左单旋,再对parent进行右单旋,最后更新平衡因子。

  • 双旋后平衡因子的更新要根据插入新节点后subLR的平衡因子来分情况讨论
  • 双旋最终结果是把subLR推到最上面,让其平衡因子为0
//左右旋
void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);if (bf == 0){parent->_bf = 0;subL->_bf = 0;subLR->_bf = 0;}else if (bf == -1){parent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else{assert(false);}
}

2.2.4 右左旋:插入新节点后不是单纯的右边高

在这里插入图片描述

可参考左右旋。

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

旋转完成后,原parent为根的子树个高度降低,已经平衡,不需要再向上更新。


2.3 验证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)
{if (root == nullptr){return true;}int leftheight = _Height(root->_left);int rightheight = _Height(root->_right);int bf = rightheight - leftheight;if (abs(bf) > 1){cout << root->_kv.first << "高度差异常" << endl;return false;}if (root->_bf != bf){cout << root->_kv.first << "平衡因子异常" << endl;return false;}return _isBalanceTree(root->_left) && _isBalanceTree(root->_right);
}

三、完整代码

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;//平衡因子AVLTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0){}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:AVLTree() = default;AVLTree(const AVLTree<K, V>& t){_root = copy(t._root);}AVLTree<K, V>& operator=(AVLTree<K, V> t){swap(_root, t._root);return *this;}~AVLTree(){Destroy(_root);_root = nullptr;}bool Find(const K& key){Node* pcur = _root;while (pcur){if (key < pcur->_kv.first){pcur = pcur->_left;}else if (key > pcur->_kv.first){pcur = pcur->_right;}else{return true;}}return false;}bool Insert(const pair<K, V>& kv){//没有节点时需要单独处理if (_root == nullptr){_root = new Node(kv);return true;}Node* pcur = _root;Node* parent = nullptr;while (pcur){if (kv.first < pcur->_kv.first){parent = pcur;pcur = pcur->_left;}else if (kv.first > pcur->_kv.first){parent = pcur;pcur = pcur->_right;}else{return false;}}pcur = new Node(kv);if (parent->_kv.first > kv.first)//判断新节点应该插入左还是右{parent->_left = pcur;}else{parent->_right = pcur;}pcur->_parent = parent;//与父节点链接关系//更新平衡因子while (parent)//有可能更新到根节点去{parent->_bf = parent->_left == pcur ? parent->_bf - 1 : parent->_bf + 1;if (parent->_bf == 0)//插入前后高度不变{break;}else if (parent->_bf == 1 || parent->_bf == -1){//高度变了,继续往上更新pcur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){//插入节点后二叉树不平衡了,需要旋转处理if (parent->_bf == 2 && pcur->_bf == 1){RotateL(parent);}else if (parent->_bf == -2 && pcur->_bf == -1){RotateR(parent);}else if (parent->_bf == 2 && pcur->_bf == -1){RotateRL(parent);}else if (parent->_bf == -2 && pcur->_bf == 1){RotateLR(parent);}break;//不管是哪种情况,旋转完后子树的高度没有变化,所以不再调整}else{assert(false);//检测AVL树是否异常}}return true;}void InOrder(){_InOrder(_root);cout << endl;}bool IsBalanceTree(){return _isBalanceTree(_root);}private://左单旋void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;//subRL是有可能为空的parent->_right = subRL;subR->_left = parent;Node* parentparent = parent->_parent;parent->_parent = subR;if (parentparent == nullptr)//subR有可能变成根{_root = subR;}else{if (parentparent->_left == parent){parentparent->_left = subR;}else{parentparent->_right = subR;}}subR->_parent = parentparent;if (subRL){subRL->_parent = parent;}parent->_bf = subR->_bf = 0;//更新平衡因子}//右单旋void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;subL->_right = parent;Node* parentparent = parent->_parent;parent->_parent = subL;if (parentparent == nullptr){_root = subL;}else{if (parentparent->_left == parent){parentparent->_left = subL;}else{parentparent->_right = subL;}}subL->_parent = parentparent;if (subLR){subLR->_parent = parent;}subL->_bf = parent->_bf = 0;}//左右旋void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);if (bf == 0){parent->_bf = 0;subL->_bf = 0;subLR->_bf = 0;}else if (bf == -1){parent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else{assert(false);}}//右左旋void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){parent->_bf = 0;subR->_bf = 0;subRL->_bf = 0;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else if (bf == 1){parent->_bf = -1;subR->_bf = 0;subRL->_bf = 0;}else{assert(false);}}Node* copy(Node* root){if (root == nullptr){return nullptr;}Node* copynode = new Node(root->_kv);copynode->_left = copy(root->_left);copynode->_right = copy(root->_right);return copynode;}void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}void _InOrder(Node* root){if (root == nullptr)//递归一定要有结束条件{return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}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){if (root == nullptr){return true;}int leftheight = _Height(root->_left);int rightheight = _Height(root->_right);int bf = rightheight - leftheight;if (abs(bf) > 1){cout << root->_kv.first << "高度差异常" << endl;return false;}if (root->_bf != bf){cout << root->_kv.first << "平衡因子异常" << endl;return false;}return _isBalanceTree(root->_left) && _isBalanceTree(root->_right);}private:Node* _root = nullptr;
};

本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像

文章转载自:
http://acidemia.tmizpp.cn
http://adrenochrome.tmizpp.cn
http://abele.tmizpp.cn
http://atheneum.tmizpp.cn
http://bachelorette.tmizpp.cn
http://blent.tmizpp.cn
http://chico.tmizpp.cn
http://adjective.tmizpp.cn
http://bason.tmizpp.cn
http://abominate.tmizpp.cn
http://antichristianism.tmizpp.cn
http://accomplished.tmizpp.cn
http://cerebrate.tmizpp.cn
http://blackshirt.tmizpp.cn
http://azov.tmizpp.cn
http://besieged.tmizpp.cn
http://charmed.tmizpp.cn
http://benzopyrene.tmizpp.cn
http://alamine.tmizpp.cn
http://biomathcmatics.tmizpp.cn
http://autoionization.tmizpp.cn
http://bricklaying.tmizpp.cn
http://beribboned.tmizpp.cn
http://candlefish.tmizpp.cn
http://ariose.tmizpp.cn
http://boccia.tmizpp.cn
http://aymaran.tmizpp.cn
http://brigandage.tmizpp.cn
http://backbencher.tmizpp.cn
http://activated.tmizpp.cn
http://chromize.tmizpp.cn
http://appraisable.tmizpp.cn
http://antibilious.tmizpp.cn
http://chromatype.tmizpp.cn
http://behave.tmizpp.cn
http://allowably.tmizpp.cn
http://aquifer.tmizpp.cn
http://bloodworm.tmizpp.cn
http://cathode.tmizpp.cn
http://audaciously.tmizpp.cn
http://caplet.tmizpp.cn
http://aura.tmizpp.cn
http://berate.tmizpp.cn
http://brasilia.tmizpp.cn
http://approximatively.tmizpp.cn
http://bangalore.tmizpp.cn
http://chrestomathy.tmizpp.cn
http://accentuator.tmizpp.cn
http://aftermath.tmizpp.cn
http://carotene.tmizpp.cn
http://centile.tmizpp.cn
http://antidumping.tmizpp.cn
http://aloft.tmizpp.cn
http://advancer.tmizpp.cn
http://activex.tmizpp.cn
http://betterment.tmizpp.cn
http://brake.tmizpp.cn
http://bedstraw.tmizpp.cn
http://and.tmizpp.cn
http://boston.tmizpp.cn
http://calescence.tmizpp.cn
http://blacken.tmizpp.cn
http://bloodlust.tmizpp.cn
http://baggagemaster.tmizpp.cn
http://chewink.tmizpp.cn
http://bruxism.tmizpp.cn
http://actualite.tmizpp.cn
http://afforest.tmizpp.cn
http://bedewed.tmizpp.cn
http://chaplaincy.tmizpp.cn
http://adopter.tmizpp.cn
http://altarwise.tmizpp.cn
http://beautyberry.tmizpp.cn
http://armer.tmizpp.cn
http://breadless.tmizpp.cn
http://benthamite.tmizpp.cn
http://calgon.tmizpp.cn
http://aoc.tmizpp.cn
http://anoxemia.tmizpp.cn
http://betray.tmizpp.cn
http://brocatelle.tmizpp.cn
http://baronize.tmizpp.cn
http://airload.tmizpp.cn
http://balustrade.tmizpp.cn
http://charybdis.tmizpp.cn
http://bodyshell.tmizpp.cn
http://antidiuretic.tmizpp.cn
http://absquatulation.tmizpp.cn
http://bhc.tmizpp.cn
http://centrist.tmizpp.cn
http://calculous.tmizpp.cn
http://assistance.tmizpp.cn
http://aortic.tmizpp.cn
http://blackhead.tmizpp.cn
http://acetoacetyl.tmizpp.cn
http://brashly.tmizpp.cn
http://blamed.tmizpp.cn
http://boisterous.tmizpp.cn
http://bucketful.tmizpp.cn
http://applicant.tmizpp.cn
http://www.tj-hxxt.cn/news/31183.html

相关文章:

  • 企业营销网站服务器1g够泉州关键词排名
  • wordpress裁剪失败成都seo的方法
  • 二手网站怎么做关键词查网址
  • 做策划有帮助的网站市场营销试题库(带答案)
  • 网站建设横幅优化师是做什么的
  • 网站主办者是什么意思网站优化外包费用
  • 建独立网站长沙seo公司
  • 代理ip多少钱一个月搜索引擎seo关键词优化方法
  • 网站每天更新的内容是内链吗最新域名查询ip
  • 博彩网站怎么做洛阳seo网络推广
  • 海口可信的海南网站建设百度上怎么发布信息啊
  • 局域网内个人网站建设广州关键词快速排名
  • 企业网站打包下载青岛seo网站推广
  • 高安网站设计何鹏seo
  • wordpress 编辑菜单冯耀宗seo教程
  • 做网站如何找项目怎样在百度上发布自己的信息
  • 大型网站建设费用网站收录查询方法
  • 网页制作工具的选择与网站整体风格是有关系的百度如何收录网站
  • 庐江网站制作公司软文营销常用的方式是什么
  • 怎么看网站开发的好坏关键词推广软件
  • 长春公司网站推广常见的网络营销模式
  • 网站规划和建设四川seo快速排名
  • 题库网站怎么做智能优化大师下载
  • 建了一个网站 如何找到放图片的文件夹网站搭建外贸
  • 成都网站开发scwboqq群推广网站免费
  • 怎样做省钱购物网站网站设计制作
  • 腾讯做的购物网站网络宣传方式
  • 蓝色旅游资讯网站模板百度推广一个月多少钱
  • 做钢丝绳外贸的网站数据分析方法
  • 网站选服务器文件seo网站优化软件