AVL树的理解和实现[C++]

文章目录

  • AVL树
    • AVL树的规则或原理
  • AVL树的实现
    • 1.节点的定义
    • 2.功能和接口等的实现
      • 默认构造函数,析构函数
      • 拷贝构造函数
      • 插入
      • 搜索
      • 打印函数
      • 检查是否为平衡树,检查平衡因子
      • 旋转

AVL树

AVL树,全称Adelson-Velsky和Landis树,是一种自平衡的二叉搜索树。它于1962年由苏联科学家Adelson-Velsky和Landis首次提出。AVL树具有以下特点:树中任一节点的左右子树高度差不超过1,因此AVL树是一种严格平衡的二叉搜索树。在AVL树上进行查找、插入和删除操作的时间复杂度均为O(log n),大大提高了搜索效率。

AVL树的规则或原理

当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

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

AVL树的实现

1.节点的定义

首先,我们定义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 factor(平衡因子)AVLTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _bf(0){}
};

2.功能和接口等的实现

默认构造函数,析构函数

template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public://默认构造函数,用来初始化AVL树,将根节点置空来表示树是空的AVLTree() = default;//析构函数~AVLTree(){Destroy(_root);_root = nullptr;}
private:void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}
private:Node* _root = nullptr;
};

拷贝构造函数

template<class K, class V>
class AVLTree
{//拷贝构造AVLTree(const AVLTree<K, V>& t){_root = Copy(t._root);}private://用递归来进行赋值AVL树的节点Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* newRoot = new Node(root->_key, root->_value);newRoot->_left = Copy(root->_left);newRoot->_right = Copy(root->_right);return newRoot;}private:Node* _root = nullptr;
};

插入

template<class K, class V>
class AVLTree
{	
private:bool Insert(const 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 (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = 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){// 不平衡了,旋转处理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{RotateLR(parent);}break;}else{assert(false);}}return true;}private:Node* _root = nullptr;
};

搜索

template<class K, class V>
class AVLTree
{
private:Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return cur;}}return nullptr;}private:Node* _root = nullptr;
};

打印函数

template<class K, class V>
class AVLTree
{void InOrder(){_InOrder(_root);cout << endl;}	
private:void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}
private:Node* _root = nullptr;
};

检查是否为平衡树,检查平衡因子

template<class K, class V>
class AVLTree
{
bool IsBanlanceTree(){return _IsBanlanceTree(_root);}
private://计算平衡因子函数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 _IsBanlanceTree(Node* root){//空树返回真if (nullptr == root){return true;}//计算root的平衡因子:即root左右子树高度差int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);int diff = rightHeight - leftHeight;//如果计算出的平衡因子与root的平衡因子不相等//或,root平衡因子的绝对值超过一,则不是AVL树/*if (abs(diff) < 2 || root->_bf != diff){return false;}*/if (abs(diff) >= 2){cout << root->_kv.first << "高度差异常" << endl;return false;}if (root->_bf != diff){cout << root->_kv.first << "平衡因子异常" << endl;return false;}//root的左右都是AVL树那么概述一定是AVL树return _IsBanlanceTree(root->_left) && _IsBanlanceTree(root->_right);}
private:Node* _root = nullptr;
};

旋转

template<class K, class V>
class AVLTree
{void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* parentParent = parent->_parent;csubR->_left = parent;parent->_parent = subR;if (parentParent == nullptr){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;}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;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;}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);}}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;}}
private:Node* _root = nullptr;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/49311.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java IO模型深入解析:BIO、NIO与AIO

Java IO模型深入解析&#xff1a;BIO、NIO与AIO 一. 前言 在Java编程中&#xff0c;IO&#xff08;Input/Output&#xff09;操作是不可或缺的一部分&#xff0c;它涉及到文件读写、网络通信等方面。Java提供了多种类和API来支持这些操作。本文将从IO的基础知识讲起&#xff…

智慧职校就业管理:开启校园招聘会新模式

在智慧职校的就业管理系统中&#xff0c;校园招聘会的出现&#xff0c;为学生们提供了一个展示自我、探寻职业道路的舞台&#xff0c;同时也为企业搭建了一座直面未来之星的桥梁。这一功能&#xff0c;凭借其独特的优势与前沿的技术&#xff0c;正在重新定义校园与职场之间的过…

映美精彩色相机IFrameQueueBuffer转halcon的HObject

1.之前写了黑白IFrameQueueBuffer转halcon的HObject&#xff0c;下载这边文件写&#xff0c;彩色IFrameQueueBuffer转halcon的HObject 2.相机的部署跟黑白的一样&#xff0c;不同的是取图的格式改变 if (CamerTakeImageOne._camer_take_image_static._camer_is_exit){textbox_m…

【JVM基础06】——组成-直接内存详解

目录 1- 引言&#xff1a;直接内存概述1-1 直接内存是什么&#xff1f;直接内存的定义(What)1-2 为什么用直接内存&#xff1f;Java程序对直接内存的使用 (Why) 2- ⭐核心&#xff1a;详解直接内存(How)2-1 文件拷贝案例介绍对比常规 IO(BIO) 和 NIO常规 IO 的操作流程NIO 的操…

LeetCode 热题 HOT 100 (009/100)【宇宙最简单版】

【图论】No. 0207 课程表【中等】&#x1f449;力扣对应题目指路 希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#xff01…

小公司怎么申请企业邮箱?

小公司申请企业邮箱需要考虑哪些因素&#xff1f;小公司选择企业邮箱需考虑成本、功能、安全、支持等因素。小公司怎么申请企业邮箱呢&#xff1f;注册企业邮箱需填写企业信息、选择套餐并添加用户。 一、小公司申请企业邮箱考虑的因素 1、成本效益分析 预算规划&#xff1a…

Try ubuntu core (by quqi99)

作者&#xff1a;张华 发表于&#xff1a;2024-07-20 版权声明&#xff1a;可以任意转载&#xff0c;转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明(http://blog.csdn.net/quqi99) try ubuntu core on qemu #ovmf is to ensure compatibility with the re…

Rust编程-高级特性

unsafe&#xff1a;内存不安全 内存安全问题&#xff0c;例如空指针解引用 关键字unsafe来切换到不安全模式&#xff0c;并在被标记后的代码块中使用不安全代码 使用unsafe告诉编译器后面代码安全性自行负责 因为电脑硬件安全问题&#xff0c;必须编写可能不安全的代码 可以将…

matlab--legend利用for循环添加图例

第一种方法 %% 第一种方法 R 1:4; THETA1 atand(R./1.8); legend_name {}; for i 1:4THETA atand(R(i)./1.8);intTheta floor(THETA);R_THERA 1.8 - (R(i)./tand(intTheta-10:intTheta10));R_THERA1 1.8 - (R(i)/tand(intTheta));plot(R_THERA);grid on;hold onlegend…

在字符串的 格式化 与 反格式化 中用到的 模块 和 方法

目录 一&#xff0c;Open函数使用 二&#xff0c;Json与pickle 一&#xff0c;json模块 1. 将 Python 对象转换为 JSON 字符串 2. 将 JSON 字符串解析为 Python 对象 3. 读取和写入 JSON 文件 4. 处理 JSON 中的特殊数据类型 5. 错误处理 二&#xff0c;pikel模块 1. …

领夹麦克风哪个品牌好,电脑麦克风哪个品牌好,热门麦克风推荐

​在信息快速传播的时代&#xff0c;直播和视频创作成为了表达与交流的重要方式。对于追求卓越声音品质的创作者而言&#xff0c;一款性能卓越的无线麦克风宛如一把利剑。接下来&#xff0c;我要为大家介绍几款备受好评的无线麦克风&#xff0c;这些都是我在实际使用中体验良好…

淘客返利系统中的服务发现与注册机制详解

淘客返利系统中的服务发现与注册机制详解 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;在本文中&#xff0c;我们将深入探讨淘客返利系统中的服务发现与注册机制&#xff0c;并结合Java代码进行详细…

【Linux常用命令】之sed命令

Linux常用命令之sed命令 文章目录 Linux常用命令之sed命令常用命令之sed背景介绍 总结 作者简介 听雨&#xff1a;一名在一线从事多年研发的程序员&#xff0c;从事网站后台开发&#xff0c;熟悉java技术栈&#xff0c;对前端技术也有研究&#xff0c;同时也是一名骑行爱好者。…

SpringBoot大模型流式接口

话不多说&#xff0c;直接上货 import cn.hutool.core.util.IdUtil; import com.alibaba.fastjson.JSONObject; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.Re…

人工智能(AI)在办公场所的广泛应用

人工智能&#xff08;AI&#xff09;在办公场所的广泛应用正逐步改变着我们的工作方式和效率。随着技术的进步&#xff0c;越来越多的公司和组织开始采用各种AI技术来优化工作流程、提升生产力&#xff0c;并提供更好的用户体验。以下是人工智能在办公方面的一些主要作用和影响…

linux学习笔记整理: 关于linux:nginx服务器 2024/7/20;

nginx服务器: 自理解: nginx是一种分发式服务器,统一进入的接口,并将进入的用户进行指定性分发给不同服务器地址交互; Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。其特点是占有内…

Java 如何获取一个 class 的所有属性和方法

&#x1f446;&#x1f3fb;&#x1f446;&#x1f3fb;&#x1f446;&#x1f3fb;关注博主&#xff0c;让你的代码变得更加优雅。 前言 Hutool 是一个小而全的Java工具类库&#xff0c;通过静态方法封装&#xff0c;降低相关API的学习成本&#xff0c;提高工作效率&#xf…

LeetCode 125.验证回文串 C++写法

LeetCode 125.验证回文串 C写法 思路&#x1f914;&#xff1a; 我们不对字符串进行删除&#xff0c;这样效率太低了&#xff0c;所以可以左右开工&#xff0c;下标begin和end遇到不是字母数字字符的就跳过&#xff0c;当两边都是字母就进行比对&#xff0c;一样就继续往后走&a…

sqlserver 跨服务器进行数据增删改查

--连接远程服务器 exec sp_addlinkedserver 目标服务器名&#xff08;自定义取名&#xff09;, , SQLOLEDB , 192.168.180.18&#xff08;目标服务器IP&#xff09; --登录远程服务器 exec sp_addlinkedsrvlogin 目标服务器名, false ,null, &#xff08;用户名&#xff09…

PCL 批量处理点云文件

系列文章目录 文章目录 系列文章目录前言一、PCL是什么&#xff1f;二、配置PCL环境三、使用步骤1.引入库2.主函数 总结 前言 点云处理时往往会需要对多个点云进行处理&#xff0c;比如在预处理&#xff0c;保存点云时。下面提供一个简单的点云批量转换例子&#xff0c;PCD文件…