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;
};
相关文章:

AVL树的理解和实现[C++]
文章目录 AVL树AVL树的规则或原理 AVL树的实现1.节点的定义2.功能和接口等的实现默认构造函数,析构函数拷贝构造函数插入搜索打印函数检查是否为平衡树,检查平衡因子旋转 AVL树 AVL树,全称Adelson-Velsky和Landis树,是一种自平衡…...
云计算遭遇的主要安全威胁
以下是详细说明云计算遭遇的所有主要安全威胁: 1. 数据泄露 描述:数据泄露是指未经授权的情况下访问和获取敏感数据。云计算环境中的数据泄露通常由于不安全的配置、软件漏洞或内部威胁造成。 案例: Capital One数据泄露:2019…...

[MySQL]02 存储引擎与索引,锁机制,SQL优化
Mysql存储引擎 可插拔式存储引擎 索引是在存储引擎底层上实现的 inno DB MySQL默认存储引擎: inno DB高可靠性和高性能的存储引擎 DML操作遵循ACID模型支持事务行级锁,提高并发访问性能支持外键 约束,保证数据完整性和可靠性 MySAM MySAM是MySQL的早期引擎 特点: 不支持事…...
ld,GNU 链接器介绍以及命令行参数详解
ld,GNU 链接器介绍以及命令行参数详解 当我们使用GCC编译源代码生成可执行程序,经过预处理、汇编、编译、链接四个阶段。 链接器(Linker)将多个目标文件和库文件链接起来,链接器还解决目标文件之间的符号引用ÿ…...
[web]-反序列化-base64
看到源码 <?php error_reporting(0); class A {public $contents "hello ctfer";function __toString(){if ((preg_match(/^[a-z]/i,$this->contents))) {system("echo $this->contents");return 111;}else{return "...";}} }functi…...

【医学影像】RK3588+FPGA:满足远程诊疗系统8K音视频编解码及高效传输需求
医学影像 提供基于Intel平台、NXP平台、Rockchip平台的核心板、Mini-ITX主板、PICO-ITX主板以及工业整机等计算机硬件。产品板载内存,集成超高清编码/解码视频引擎,具有出色的数据处理能力和图形处理能力,功能高集成,可应用于超声…...

昇思25天学习打卡营第16天|基于MindSpore通过GPT实现情感分类
文章目录 昇思MindSpore应用实践1、基于MindSpore通过GPT实现情感分类GPT 模型(Generative Pre-Training)简介imdb影评数据集情感分类 2、Tokenizer导入预训练好的GPT3、基于预训练的GPT微调实现情感分类 Reference 昇思MindSpore应用实践 本系列文章主…...

服务器借助笔记本热点WIFI上网
一、同一局域网环境 1、当前环境,已有交换机组网环境,服务器已配置IP信息。 设备ip服务器125.10.100.12交换机125.10.100.0/24笔记本125.10.100.39 2、拓扑图 #mermaid-svg-D4moqMym9i0eeRBm {font-family:"trebuchet ms",verdana,arial,sa…...
开发实战中Git的常用操作
Git基础操作 1.初始化仓库 git init解释:在当前目录中初始化一个新的Git仓库。 2.克隆远程仓库 git clone <repository-url>解释:从远程仓库克隆一个完整的Git仓库到本地。 3.检查当前状态 git status解释:查看当前工作目录的状态…...

python调用chrome浏览器自动化如何选择元素
功能描述:在对话框输入文字,并发送。 注意: # 定位到多行文本输入框并输入内容。在selenium 4版本中,元素定位需要填写父元素和子元素名。 textarea driver.find_element(By.CSS_SELECTOR,textarea.el-textarea__inner) from …...
深入理解JS中的排序
在JavaScript开发中,排序是一项基础而重要的操作。本文将探讨JavaScript中几种常见的排序算法,包括它们的原理、实现方式以及适用场景。 1、冒泡排序 1.1、原理 通过比较相邻两个数的大小,交换位置排序:如果后一个数比前一个数小,则交换两个数的位置,重复这个过程,直…...

Kafka之存储设计
文章目录 1. 分区和副本的存储结构1. 分区和副本的分布2. 存储目录结构3. 文件描述 2. 相关配置3. 数据文件类型4. 数据定位原理LogSegment 类UnifiedLog 类 5. 副本数据同步HW水位线LEO末端偏移量HW更新原理 6. 数据清除 1. 分区和副本的存储结构 在一个多 broker 的 Kafka 集…...
Python面试整理-Python中的函数定义和调用
在Python中,函数是一种封装代码的方式,使得代码模块化和复用性更强。定义和调用函数是Python编程中的基本技能。以下是关于如何在Python中定义和调用函数的详细介绍: 函数定义 函数在Python中使用def关键字进行定义。函数体开始前,通常有一个可选的文档字符串(docstring)…...

HTTP协议、Wireshark抓包工具、json解析、天气爬虫
HTTP超文本传输协议 HTTP(Hyper Text Transfer Protocol): 全称超文本传输协议,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。 HTTP 协议的重要特点: 一发一收…...

electron项目中实现视频下载保存到本地
第一种方式:用户自定义选择下载地址位置 渲染进程 // 渲染进程// 引入 import { ipcRenderer } from "electron";// 列表行数据下载视频操作,diffVideoUrl 是视频请求地址 handleDownloadClick(row) {if (!row.diffVideoUrl) {this.$message…...

基于chrome插件的企业应用
一、chrome插件技术介绍 1、chrome插件组件介绍 名称 职责 访问权限 DOM访问情况 popup 弹窗页面。即打开形式是通过点击在浏览器右上方的icon,一个弹窗的形式。 注: 展示维度 browser_action:所有页面 page_action:指定页面 可访问绝大部分api 不可以 bac…...

unittest框架和pytest框架区别及示例
unittest框架和pytest框架区别及示例 类型unittest框架pytest框架unittest框架示例pytest框架示例安装python内置的一个单元测试框架,标准库,不需要安装第三方单元测试库,需要安装使用时直接引用 import unittest安装命令:pip3 install pyte…...
IDEA性能优化方法解决卡顿
文章目录 前言一、可以采取以下措施:二、VM Options的参数解释1. 内存设置2. 性能调优3. GC(垃圾回收)调优4. 调试和诊断5. 其它设置6.设置 VM Options 的步骤: 总结 前言 我们在使用 IntelliJ IDEA的时候有时候会觉得卡顿&#x…...
Mysql集合转多行
mysql 集合转多行 SELECT substring_index(substring_index(t1.group_ids, ,, n), ,, -1) AS group_id FROM (select 908,909 as group_ids ) t1, (SELECT rownum : rownum 1 AS n FROM ( SELECT rownum : 0 ) r, orders ) t2 WHERE n < ( LENGTH( t1.group_ids ) - LENGT…...
MFC:只允许产生一个应用程序实例的具体实现
在MFC(Microsoft Foundation Class)应用程序中,如果你想限制只允许产生一个应用程序实例,通常会使用互斥体(Mutex)来实现。这可以确保如果用户尝试启动第二个实例时,它会被阻止或将焦点返回到已…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...