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

hello树先生——AVL树

AVL树

  • 一.什么是AVL树
  • 二.AVL树的结构
    • 1.AVL树的节点结构
    • 2.插入函数
    • 3.旋转调整
  • 三.平衡测试

一.什么是AVL树

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
AVL树的性质:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
  • 如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 O ( l o g 2 n ) O(log_2 n) O(log2n)
    在这里插入图片描述

二.AVL树的结构

1.AVL树的节点结构

template<class K, class V>
struct AVLTreeNode
{AVLTreeNode* _left;AVLTreeNode* _right;AVLTreeNode* _parent;pair<K, V> _kv;int _bf;AVLTreeNode(const pair<K,V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_bf(0){}
};

这里的数据存储使用pair类型的数据对,将key索引与对应数据value存储,增加了_parent保存父亲节点,增加了_bf平衡因子来衡量左右子树是否平衡。

2.插入函数

bool insert(const pair<K, V>& kv)

这里插入方式与搜索二叉树一致,只是在后面增加了平衡调整的步骤

//如果根为空if (_root == nullptr){_root = new node(kv);return true;}//找到目标值node* parent = nullptr;node* cur = _root;while (cur){//key < curif (kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else{//查重return false;}}//插入目标值cur = new node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;

调节平衡因子

while(parent)
{
//向上更新
}

如果插在左子树,则平衡因子–,否则++

if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}

判断平衡因子是否正常倘若>=2则需要旋转

			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){//需要旋转//左左高,右单旋if (parent->_bf == -2 && cur->_bf == -1){rotater(parent);}//右右高,左单旋else if(parent->_bf == 2 && cur->_bf == 1){rotatel(parent);}//右左高,先右旋成为右右高,再左旋else if (parent->_bf == 2 && cur->_bf == -1){rotaterl(parent);}else{rotatelr(parent);}break;}else{//大问题assert(false);}

3.旋转调整

AVL树的旋转分为四种,左单旋,右单旋,左右双旋和右左双旋。

1.右单旋

	void rotater(node* parent)

在这里插入图片描述
当插入new节点时,60节点会左右失衡,我们称60为parent,30为subl,则平衡因子会分别变为-2,-1,成为左左高模型,此时使用右单旋。
由于搜索树特性:30<b<60<c,所以可以将右方降下去,从而达到平衡。

  • 传入旋转点parent

  • 记录关键节点,防止旋转后丢失
    在这里插入图片描述

		node* subl = parent->_left;node* sublr = subl->_right;
  • 将parent的左指向sublr,若sublr为空节点,则不链接父亲节点否则链接
  • 将subl的右指向parent,同时链接父亲节点
		parent->_left = sublr;if (sublr)sublr->_parent = parent;subl->_right = parent;parent->_parent = subl;//保存父节点node* ppnode = parent->_parent;subl->_parent = ppnode;
  • 考虑parent是否为根,是否链接parent的父亲节点
		//考虑parent是否为根if (ppnode == nullptr){_root = subl;subl->_parent = nullptr;}else{subl->_parent = ppnode;if (ppnode->_left == parent){ppnode->_left = subl;}else{ppnode->_right = subl;}}
  • 修改平衡因子
parent->_bf = subl->_bf = 0;

2.左单旋
大体思路与右单旋相同
在这里插入图片描述

	void rotatel(node* parent){node* subr = parent->_right;node* subrl = subr->_left;parent->_right = subrl;if (subrl)subrl->_parent = parent;subr->_left = parent;//保存父节点node* ppnode = parent->_parent;parent->_parent = subr;subr->_parent = ppnode;//考虑parent是否为根if (ppnode == nullptr){_root = subr;subr->_parent = nullptr;}else{subr->_parent = ppnode;if (ppnode->_left == parent){ppnode->_left = subr;}else{ppnode->_right = subr;}}//调节平衡因子parent->_bf = subr->_bf = 0;}

3.左右双旋

void rotatelr(node* parent)

通常双旋有三种情况,在b里插入新节点,在c里插入新节点,或者b,c都为空
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

记录sul的平衡因子,方便判断是哪种情况

		node* subl = parent->_left;node* sublr = subl->_right;int bf = subl->_bf;rotatel(subl);rotater(parent);
		if (bf == -1){subl->_bf = 0;parent = 1;}else if (bf == 1){subl->_bf = -1;parent->_bf = 0;}else if (bf == 0){subl->_bf = 0;parent->_bf = 0;}sublr->_bf = 0;

每一种情况平衡因子不同,所以需要画图分别讨论
** 4.右左双旋**

void rotaterl(node* parent){node* subr = parent->_right;node* subrl = subr->_left;int bf = subr->_bf;rotater(subr);rotater(parent);if (bf == -1){subr->_bf = 1;parent = 0;}else if (bf == 1){subr->_bf = 0;parent->_bf = -1;}else if (bf == 0){subr->_bf = 0;parent->_bf = 0;}subrl->_bf = 0;}

三.平衡测试

判断是否平衡

    bool _IsBalance(node* root){if (root == nullptr){return true;}int leftheight = _height(root->_left);int rightheight = _height(root->_right);if (abs(leftheight - rightheight) >= 2){return false;}//判断节点平衡因子是否正确if (root->_bf != (rightheight - leftheight)){return false;}return _IsBalance(root->_left) && _IsBalance(root->_right);}

在这里插入图片描述
在这里插入图片描述


http://www.mrgr.cn/news/16556.html

相关文章:

  • MySQL基础学习:MySQL主从复制如何实现
  • 组织培训如何分组?
  • C++基础(1)——入门知识
  • 某视频云平台存在未授权窃取用户凭据漏洞
  • linux常用命令总结
  • MPLS VPN的配置
  • ES6更新的内容中什么是proxy
  • 封装_受保护的属性和方法
  • day_60
  • 基于jstat 分析垃圾回收情况,进行JVM调优
  • 《C++20 特性综述》
  • 【fastapi】fastapi的hello world
  • 质数、约数详解
  • centOS服务器上如何安装宝塔面板-两分钟快速配置
  • 【web开发】Spring Boot 快速搭建Web项目(二)
  • 2024.8.29顺丰笔试算法题真题
  • PMNet
  • python网络爬虫(三)——爬虫攻防
  • 【算法】前缀和例题讲解
  • 基于STM32的智能物料运载小车:OpenMV和OpenCV结合图像识别与运动控制算法优化(代码示例)