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

丹东网站seo网页在线生成器

丹东网站seo,网页在线生成器,免费设计logo图标生成器,wordpress主题 芯片⭐上篇文章:34.二叉树进阶3(CSTL 关联式容器,set/map的介绍与使用)-CSDN博客 ⭐本篇代码:c学习/19.map和set的使用用与模拟 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) ⭐标⭐是比较重要的部分 一. 二…

⭐上篇文章:34.二叉树进阶3(C++STL 关联式容器,set/map的介绍与使用)-CSDN博客

⭐本篇代码:c++学习/19.map和set的使用用与模拟 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)

⭐标⭐是比较重要的部分

一. 二叉搜索树的缺点

        之前文章中提到,普通的二叉搜索树在某些情况下会退出成链表,或者根节点的左右子树的高度差非常大。这个时候就会导致其搜索效率由 O(logN) -> O(N)。

        为了解决这个问题,计算机科学家提供了AVL树。AVL树一种平衡二叉搜索树,通过平衡因子和旋转操作来保证二叉搜索树是平衡的。

二. AVL树及其特点

1 AVL树是一颗二叉搜索树,满足二叉搜索树的性质

2 AVL树每一个节点中有一个平衡因子,表示该节点左右子树的高度差的绝对值,且该值不能超过1(即左右子树高度差不能超过1)

        可以看到,通过平衡因子可以保证AVL树是高度平衡的!AVL树在每一次插入新节点之后都要检验该节点和其父节点的平衡因子,一旦检测到平衡因子的值超过1,就要通过旋转操作来调整平衡因子。

三. AVL树的节点和旋转操作图解

3.1 AVL树节点

//节点
template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;//节点的双亲,用于更新平衡因子int _bf;//平衡因子 balance factor pair<K, V> _kv;//构造函数AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0), _kv(kv){}
};

二叉树一般都是存储键值对<k,v>。AVL树需要一个平衡因子bf

3.2 AVL树结构 

template<class K, class V>
class AVlLTree
{typedef AVLTreeNode<K, V> Node;
public:bool Insert(const pair<K, V>& kv){}
private:Node* _root;
};

3.3 AVL树的插入操作 ⭐

        AVL树的插入操作和二叉搜索树几乎一样,不过在插入节点之后要根据平衡因子才调整整棵树的结构。

a 左单旋

        如果一个节点的平衡因子为2,即右子树比左子树高2则需要对该节点进行左单旋

代码如下:

//右右,左单旋.一共需要调整6条线,四个节点void RotateLeft(Node* parent){if (!parent)return;Node* ppNode = parent->_parent;//要旋转节点的父亲Node* SubR = parent->_right;//要旋转节点的右孩子Node* SubRLeft = SubR->_left;//要旋转节点右孩子的左孩子//一:调整节点parent->_right = SubRLeft;if (SubRLeft)SubRLeft->_parent = parent;SubR->_left = parent;parent->_parent = SubR;//1.parent是根,现在SubR是根//2.parent是整棵树的子树,找到其父亲,旋转完成后,让subR与其父亲相连接if (_root == parent){_root = SubR;SubR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubR;}else{ppNode->_right = SubR;}SubR->_parent = ppNode;}//二:更新平衡因子parent->_bf = SubR->_bf = 0;}

b 右单旋 

        如果一个节点的左子树比右子树高2,则需要对该节点进行右单旋

代码如下:

//左左,右单旋void RotateRight(Node* parent){if (!parent)return;Node* ppNode = parent->_parent;Node* SubL = parent->_left;Node* SubLRight = SubL->_right;//1.旋转,调整节点parent->_left = SubLRight;if (SubLRight)SubLRight->_parent = parent;SubL->_right = parent;parent->_parent = SubL;if (_root == parent){_root = SubL;SubL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubL;}else{ppNode->_right = SubL;}SubL->_parent = ppNode;}//2.更新平衡因子//旋转之后,subL为子树根,左子树高度为h+1,右子树为h+parent高度1.左右子树高度一样,平衡因子为0//parent左右子树高度也相等,平衡因子为0parent->_bf = SubL->_bf = 0;}

c 左双旋

        如果新增节点在较高右子树的左侧,则需要两次旋转。如下图

双旋可以复用单旋的代码

//右左void RotateRightLeft(Node* parent){//注意控制三个节点的平衡因子Node* SubR = parent->_right;Node* SubRL = SubR->_left;int bf = SubRL->_bf;RotateRight(parent->_right);    //上图旋转10RotateLeft(parent);             //上图旋转5//对应图来理解平衡因子if (bf == -1)//右左节点的左边插入{parent->_bf = 0;SubR->_bf = 1;}else if (bf == 1)//右左节点的右边插入{SubR->_bf = 0;parent->_bf = -1;}else if (bf == 0)//此时SubRL就是新增节点{parent->_bf = 0;SubR->_bf = 0;}//此时右左节点是根节点SubRL->_bf = 0;}

 c 右双旋

        如果新增节点在较高左子树的右侧,则需要两次旋转。如下图

//左右,先左旋parent->left,再右旋parentvoid RotateLeftRight(Node* parent){Node* SubL = parent->_left;Node* SubLR = SubL->_right;int bf = SubLR->_bf;RotateLeft(SubL);    //上图旋转5RotateRight(parent); //上图旋转10//更新平衡因子if (bf == 1){parent->_bf = 0;SubL->_bf = -1;}else if (bf == -1){SubL->_bf = 0;parent->_bf = 1;}else if (bf == 0){SubL->_bf = 0;parent->_bf = 0;}//左右节点为根节点SubLR->_bf = 0;}

注意,每一次旋转之后都要更新平衡因子

四. 二叉树插入完整代码

#pragma once
#include<iostream>
#include<queue>
#include<string>
using namespace std;//AVL树		(高度平衡二叉搜索树)
//1.是二叉搜索树
//2.树及所有子树都要满足左右左右子树的高度差不超过1//为了方便实现,我们在这里引入了平衡因子的概念,其值范围只能是0,1,-1(平衡因子不是必须的)
//平衡因子=右子树的高度-左子树的高度
//这样就能够控制其高度位O(logN)//节点
template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;//节点的双亲,用于更新平衡因子int _bf;//平衡因子 balance factor pair<K, V> _kv;//构造函数AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0), _kv(kv){}
};//AVLTree
//1.按照搜索树的规则插入
//2.更新平衡因子
//3.如果没有出现违规的平衡因子,插入结束
//4.如果有存在违规的平衡因子,需要旋转
template<class K, class V>
class AVlLTree
{typedef AVLTreeNode<K, V> Node;
public://一个节点的插入,只会影响其祖先的平衡因子,所以只要判断其祖先的平衡因子即可//1.如果cur是其父亲的左,parent->_bf--.如果cur是其父亲的右,parent->_bf++//2.在这些祖先中,更新完,parent->_bf==0,说明parent的高度不变,更新结束,插入完成(把这颗parent为根的子树矮的填上了)//3.更新完parent,parent->_bf==1 or -1,parent高度变了,继续往上更新(说明更新前parent->_bf==0,parent的高度变了)\//4.如果更新完parent的bf,parent->_bf==2, or -2,parent的所在子树不平衡,需要旋转处理,旋转后插入结束bool Insert(const pair<K, V>& kv){//1.先按搜索树进行插入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->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv);if (parent->_kv.first > kv.first){parent->_left = cur;cur->_parent = parent;//要将cur与其父亲链接}else{parent->_right = cur;cur->_parent = parent;}//2.从插入节点开始对这个节点及所有祖先节点更新平衡因子while (parent){if (parent->_right == cur){parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0){//parent所在子树高度不变,更新结束break;}else if (parent->_bf == 1 || parent->_bf == -1){//parent所在子树高度变了,有0变1或者-1,此时继续向上更新cur = parent;parent = parent->_parent;}else //if (parent->_bf == 2 || parent->_bf == -2){//parent所在子树出现问题,需要旋转处理//1.旋转完成后,它还得是完整的搜索树//2.旋转完成后,它要变平衡//旋转方法if (parent->_bf == 2)//左旋{if (cur->_bf == 1)//右右,直接对parent左单旋{//1.左单旋//将subR的左边给parent的右边(parent的右边指向subR的左边)//将parent变为subR的左边(subR的左边指向parent)RotateLeft(parent);}else if (cur->_bf == -1)//右左,先对parent->right右单旋,再对parent左单旋{//左双旋//先右单旋cur,让parent变为右右//再左单旋parentRotateRightLeft(parent);} }else if (parent->_bf == -2){	if (cur->_bf == -1)//左左,直接对parent右单旋{//右单旋RotateRight(parent);}else if (cur->_bf == 1)//左右,对parent->left左单旋,再对parent右单旋{//右双旋//先左单旋cur,让parenttt变为左左//再右单旋parent//此时parent左右这个节点为根RotateLeftRight(parent);}}//旋转完成后之间跳出即可,这是由于旋转让我平衡了,高度恢复到了插入新节点之前的高度(即高度不会变化)//如果是子树,对上层节点不会有影响。更新结束,跳出即可break;			}}return true;}void InOrder(){_InOrder(_root);cout << endl;}
private://右右,左单旋.一共需要调整6条线,四个节点void RotateLeft(Node* parent){if (!parent)return;Node* ppNode = parent->_parent;//要旋转节点的父亲Node* SubR = parent->_right;//要旋转节点的右孩子Node* SubRLeft = SubR->_left;//要旋转节点右孩子的左孩子//一:调整节点parent->_right = SubRLeft;if (SubRLeft)SubRLeft->_parent = parent;SubR->_left = parent;parent->_parent = SubR;//1.parent是根,现在SubR是根//2.parent是整棵树的子树,找到其父亲,旋转完成后,让subR与其父亲相连接if (_root == parent){_root = SubR;SubR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubR;}else{ppNode->_right = SubR;}SubR->_parent = ppNode;}//二:更新平衡因子parent->_bf = SubR->_bf = 0;}//左左,右单旋void RotateRight(Node* parent){if (!parent)return;Node* ppNode = parent->_parent;Node* SubL = parent->_left;Node* SubLRight = SubL->_right;//1.旋转,调整节点parent->_left = SubLRight;if (SubLRight)SubLRight->_parent = parent;SubL->_right = parent;parent->_parent = SubL;if (_root == parent){_root = SubL;SubL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubL;}else{ppNode->_right = SubL;}SubL->_parent = ppNode;}//2.更新平衡因子//旋转之后,subL为子树根,左子树高度为h+1,右子树为h+parent高度1.左右子树高度一样,平衡因子为0//parent左右子树高度也相等,平衡因子为0parent->_bf = SubL->_bf = 0;}//右左void RotateRightLeft(Node* parent){//注意控制三个节点的平衡因子Node* SubR = parent->_right;Node* SubRL = SubR->_left;int bf = SubRL->_bf;RotateRight(parent->_right);RotateLeft(parent);//对应图来理解平衡因子if (bf == -1)//右左节点的左边插入{parent->_bf = 0;SubR->_bf = 1;}else if (bf == 1)//右左节点的右边插入{SubR->_bf = 0;parent->_bf = -1;}else if (bf == 0)//此时SubRL就是新增节点{parent->_bf = 0;SubR->_bf = 0;}//此时右左节点是根节点SubRL->_bf = 0;}//左右,先左旋parent->left,再右旋parentvoid RotateLeftRight(Node* parent){Node* SubL = parent->_left;Node* SubLR = SubL->_right;int bf = SubLR->_bf;RotateLeft(SubL);RotateRight(parent);if (bf == 1){parent->_bf = 0;SubL->_bf = -1;}else if (bf == -1){SubL->_bf = 0;parent->_bf = 1;}else if (bf == 0){SubL->_bf = 0;parent->_bf = 0;}//左右节点为根节点SubLR->_bf = 0;}//中序遍历辅助函数void _InOrder(Node* root){if (!root)return;_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << " 平衡因子:" << root->_bf << endl;_InOrder(root->_right);}Node* _root;
};

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

相关文章:

  • 网站建设的具体奖罚措施新乡网络公司首选
  • 世界各大网站搜索引擎提交入口网站建设需求方案
  • 栾城区住房建设局官方网站做网站客源
  • 成都房地产网站开发广东网站建设怎么选
  • 七个php源码下载的网站学网页设计需要什么基础
  • 潍坊网站建设技术外包wordpress 改版权
  • 深圳做网站开发费用企业管理培训课程内容
  • 上海产品网站建设网站备案流程实名认证
  • 为什么要建立电子商务网站网站开发的职业认知报告
  • 广东建设职业技术学院网站科技部网站建设合同
  • 宁德营销型网站建设网络公司简介模板
  • 手机网站建设要素做一元云购网站
  • 网站一般怎么维护if设计大赛官网
  • c网站开发视频教程怎么制作app软件教程
  • 上国外网站用什么机箱好网站的标志可以修改吗
  • 网站开发端安次区建设局网站
  • 建设汽车行业网站wordpress插件下载失败
  • 无锡外贸网站制作免费网络推广的方法
  • 北京网站设计制作关键词搜索引擎优化排名案例
  • 网站移动端是什么网站建设及编辑岗位职责
  • 云南站群网站建设地方门户信息网站建设方案
  • 找网络公司做的网站到期后 备案的域名属于备案企业还是网络公司简述电子商务网站的建站流程
  • 什么网站可以做微招聘网站建设可行性报告模板
  • 新会区住房和城乡建设局网站四川建设网站公司
  • 灵犀科技网站建设wordpress 搬家 空白
  • 营销型网站备案网站首页是动态的视频怎么做
  • 怎样做一个简单的网站小程序制作流程收费
  • 某绿色园林企业网站源码免费做网站刮刮卡
  • 邗江区城乡建设局网站快站app
  • 学校网站建设情况说明上海高端建站网站