C++模拟实现AVL树

目录

1.文章概括

2.AVL树概念

3.AVL树的性质

4.AVL树的插入

5.旋转控制

1.左单旋

2. 右单旋

3.左右双旋

4.右左双旋

6.全部代码


1.文章概括

        本文适合理解平衡二叉树的读者阅读,因为AVL树是平衡二叉树的一种优化,其大部分实现逻辑与平衡二叉树是相同的,相同的部分不做过多阐述。

2.AVL树概念

        平衡二叉树主要用于查找数据,可提高查找效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。在这样的缺点下,AVL树被发明了出来。AVL树的优化点在于:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

3.AVL树的性质

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

1.它的左右子树都是AVL树;

2.左右子树高度之差(简称平衡因子)的绝对值不超过1(-1,0,1)。

AVL树 == 高度平衡二叉搜索树,说是平衡,为什么不是相等?

因为高度差不超过1,不是高度相等。

AVL树图片示例:

        如此控制后,增删改查的时间复杂度即为高度次 == O(logN)。

4.AVL树的插入

        对于一个结点的插入,分析如下:

1.新增在该结点的左,parent平衡因子减减;

2.新增在该结点的右,parent平衡因子加加;

3.更新后parent平衡因子 == 0,说明parent所在的子树的高度不变,不会再影响祖先,不用再沿着到root的路径往上更新;

4.更新后parent平衡因子 == 1 or -1,说明parent所在的子树的高度变化,会再影响祖先,需要沿着到root的路径往上更新;

5.更新后parent平衡因子 == 2 or -2,说明parent所在的子树的高度变化且不平衡,对parent所在子树进行旋转,让它平衡;

6.更到根结点。

补充说明:执行到4时会从1,2,开始继续循环,执行到3,5,6时插入结束。

旋转时需要注意的问题:

1.保持它是搜索树;

2.变成平衡树且降低这个子树的高度。

代码:

bool Insert(const T& data){Node* parent = nullptr;Node* cur = _pRoot;if (cur == nullptr){cur = new Node(data);_pRoot = cur;}while (cur){if (cur->_data > data){parent = cur;cur = cur->_pLeft;}else if (cur->_data < data){parent = cur;cur = cur->_pRight;}elsereturn false;}cur = new Node(data);if (parent->_data > data){parent->_pLeft = cur;cur->_pParent = parent;}else{parent->_pRight = cur;cur->_pParent = parent;}while (parent){if (parent->_pLeft == cur)parent->_bf--;elseparent->_bf++;if (parent->_bf == 0)return true;else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_pParent;}else{if (cur->_bf == 1 && parent->_bf == 2){RotateL(parent);}else if (cur->_bf == -1 && parent->_bf == -2){RotateR(parent);}else if (cur->_bf == -1 && parent->_bf == 2){RotateRL(parent);}else if (cur->_bf == 1 && parent->_bf == -2){RotateLR(parent);}break;}}}

        代码中,我使用了平衡因子来控制这棵树的高度。

5.旋转控制

1.左单旋

新节点插入较高右子树的右侧 --- 右右:

2. 右单旋

新节点插入较高左子树的左侧 --- 左左

3.左右双旋

 新节点插入较高左子树的右侧---左右:

4.右左双旋

新节点插入较高右子树的左侧 --- 右左:

6.全部代码

#pragma once
#include <iostream>
#include <assert.h>
#include <vector>
using namespace std;template<class T>
struct AVLTreeNode
{AVLTreeNode(const T& data = T()): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;AVLTreeNode<T>* _pRight;AVLTreeNode<T>* _pParent;T _data;int _bf;   // 节点的平衡因子
};// AVL: 二叉搜索树 + 平衡因子的限制
template<class T>
class AVLTree
{typedef AVLTreeNode<T> Node;
public:AVLTree(): _pRoot(nullptr){}// 在AVL树中插入值为data的节点bool Insert(const T& data){Node* parent = nullptr;Node* cur = _pRoot;if (cur == nullptr){cur = new Node(data);_pRoot = cur;}while (cur){if (cur->_data > data){parent = cur;cur = cur->_pLeft;}else if (cur->_data < data){parent = cur;cur = cur->_pRight;}elsereturn false;}cur = new Node(data);if (parent->_data > data){parent->_pLeft = cur;cur->_pParent = parent;}else{parent->_pRight = cur;cur->_pParent = parent;}while (parent){if (parent->_pLeft == cur)parent->_bf--;elseparent->_bf++;if (parent->_bf == 0)return true;else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_pParent;}else{if (cur->_bf == 1 && parent->_bf == 2){RotateL(parent);}else if (cur->_bf == -1 && parent->_bf == -2){RotateR(parent);}else if (cur->_bf == -1 && parent->_bf == 2){RotateRL(parent);}else if (cur->_bf == 1 && parent->_bf == -2){RotateLR(parent);}break;}}}// AVL树的验证bool IsAVLTree(){return _IsAVLTree(_pRoot);}private:// 根据AVL树的概念验证pRoot是否为有效的AVL树bool _IsAVLTree(Node* root){if (root == nullptr)return true;int leftHight = Height(root->_pLeft);int rightHight = Height(root->_pRight);if (rightHight - leftHight != root->_bf){cout << "平衡因子异常:" << root->_data << "->" << root->_bf << endl;return false;}return abs(rightHight - leftHight) < 2&& _IsAVLTree(root->_pLeft)&& _IsAVLTree(root->_pRight);}size_t Height(Node* root){if (root == nullptr)return 0;int leftHeight = Height(root->_pLeft);int rightHeight = Height(root->_pRight);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}// 右单旋void RotateR(Node* pParent) {Node* cur = pParent->_pLeft;Node* curRight = cur->_pRight;Node* parentP = pParent->_pParent;pParent->_pLeft = curRight;if(curRight)curRight->_pParent = pParent;cur->_pRight = pParent;pParent->_pParent = cur;if (parentP == nullptr){_pRoot = cur;cur->_pParent = nullptr;}else{cur->_pParent = parentP;if (parentP->_pLeft == pParent)parentP->_pLeft = cur;elseparentP->_pRight = cur;}if(curRight)curRight->_bf = 0;pParent->_bf = cur->_bf = 0;}// 左单旋void RotateL(Node* pParent){Node* cur = pParent->_pRight;Node* curLeft = cur->_pLeft;Node* parentP = pParent->_pParent;pParent->_pRight = curLeft;if(curLeft)curLeft->_pParent = pParent;cur->_pLeft = pParent;pParent->_pParent = cur;if (parentP == nullptr){_pRoot = cur;cur->_pParent = nullptr;}else{cur->_pParent = parentP;if (parentP->_pLeft == pParent)parentP->_pLeft = cur;elseparentP->_pRight = cur;}if(curLeft)curLeft->_bf = 0;pParent->_bf = cur->_bf = 0;}// 右左双旋void RotateRL(Node* pParent){Node* cur = pParent->_pRight;Node* curLeft = cur->_pLeft;int temp = curLeft->_bf;RotateR(cur);RotateL(pParent);if (temp == 0)return;else if (temp == 1){pParent->_bf = -1;cur->_bf = 0;curLeft->_bf = 0;}else if (temp == -1){pParent->_bf = 0;cur->_bf = 1;curLeft->_bf = 0;}elseassert(false);}// 左右双旋void RotateLR(Node* pParent){Node* cur = pParent->_pLeft;Node* curRight = cur->_pRight;int temp = curRight->_bf;RotateL(cur);RotateR(pParent);if (temp == 0)return;else if (temp == 1){pParent->_bf = 0;cur->_bf = -1;curRight->_bf = 0;}else if (temp == -1){pParent->_bf = 1;cur->_bf = 0;curRight->_bf = 0;}elseassert(false);}private:Node* _pRoot;
};

  

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

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

相关文章

opc da 服务器数据 转 EtherCAT项目案例

目录 1 案例说明 2 VFBOX网关工作原理 3 应用条件 4 查看OPC DA服务器的相关参数 5 配置网关采集opc da数据 6 启动EtherCAT从站转发采集的数据 7 在服务器上运行仰科OPC DA采集软件 8 案例总结 1 案例说明 在OPC DA服务器上运行OPC DA client软件查看OPC DA服务器的相…

实验9 基于WebGoat平台的SQL注入攻击

实验9 基于WebGoat平台的SQL注入攻击 1.实验目的 熟悉WebGoat平台&#xff0c;在该平台上实现SQL注入攻击。 2.实验内容 &#xff08;1&#xff09;下载webgoat-server-8.2.2.jar。 &#xff08;2&#xff09;搭建java环境。 &#xff08;3&#xff09;运行webgoat。 &#xf…

StochSync:可在任意空间中生成360°全景图和3D网格纹理

StochSync方法可以用于在任意空间中生成图像&#xff0c;尤其是360全景图和3D网格纹理。该方法利用了预训练的图像扩散模型&#xff0c;以实现零-shot生成&#xff0c;消除了对新数据收集和单独训练生成模型的需求。StochSync 结合了 Diffusion Synchronization&#xff08;DS&…

HarmonyOS 5.0应用开发——全局自定义弹出框openCustomDialog

【高心星出品】 文章目录 全局自定义弹出框openCustomDialog案例开发步骤完整代码 全局自定义弹出框openCustomDialog CustomDialog是自定义弹出框&#xff0c;可用于广告、中奖、警告、软件更新等与用户交互响应操作。开发者可以通过CustomDialogController类显示自定义弹出框…

DeepSeek模型R1服务器繁忙,怎么解决?

在当今科技飞速发展的时代&#xff0c;人工智能领域不断涌现出令人瞩目的创新成果&#xff0c;其中DeepSeek模型无疑成为了众多关注焦点。它凭借着先进的技术和卓越的性能&#xff0c;在行业内掀起了一股热潮&#xff0c;吸引了无数目光。然而&#xff0c;如同许多前沿技术在发…

AIGC-微头条爆款文案创作智能体完整指令(DeepSeek,豆包,千问,Kimi,GPT)

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列AIGC(GPT、DeepSeek、豆包、千问、Kimi)👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资…

[LLM面试题] 指示微调(Prompt-tuning)与 Prefix-tuning区别

一、提示调整(Prompt Tuning) Prompt Tuning是一种通过改变输入提示语&#xff08;input prompt&#xff09;以获得更优模型效果的技术。举个例子&#xff0c;如果我们想将一条英语句子翻译成德语&#xff0c;可以采用多种不同的方式向模型提问&#xff0c;如下图所示&#xf…

自主项目面试点总结

1、许苑–OJ判题系统 技术栈&#xff1a;Spring BootSpring Cloud AlibabaRedisMybatisMQDocker 项目地址: https://github.com/xuyuan-upward/xyoj-backend-microservice 1.1、项目介绍: 一个基于微服务的OJ系统&#xff0c;具备能够根据管理员预设的题目用例对用户提交的代…

【py】python安装教程(Windows系统,python3.13.2版本为例)

1.下载地址 官网&#xff1a;https://www.python.org/ 官网下载地址&#xff1a;https://www.python.org/downloads/ 2.64版本或者32位选择 【Stable Releases】&#xff1a;稳定发布版本&#xff0c;指的是已经测试过的版本&#xff0c;相对稳定。 【Pre-releases】&#…

CEF132 编译指南 MacOS 篇 - depot_tools 安装与配置 (四)

1. 引言 在 CEF132&#xff08;Chromium Embedded Framework&#xff09;的编译过程中&#xff0c;depot_tools 扮演着举足轻重的角色。这套由 Chromium 项目精心打造的脚本和工具集&#xff0c;专门用于获取、管理和更新 Chromium 及其相关项目&#xff08;包括 CEF&#xff…

1312:【例3.4】昆虫繁殖

1312&#xff1a;【例3.4】昆虫繁殖 时间限制: 1000 ms 内存限制: 65536 KB 提交数:60386 通过数: 29787 【题目描述】 科学家在热带森林中发现了一种特殊的昆虫&#xff0c;这种昆虫的繁殖能力很强。每对成虫过xx个月产yy对卵&#xff0c;每对卵要过两个月长成成虫…

单片机上SPI和IIC的区别

SPI&#xff08;Serial Peripheral Interface&#xff09;和IC&#xff08;Inter-Integrated Circuit&#xff09;是两种常用的嵌入式外设通信协议&#xff0c;它们各有优缺点&#xff0c;适用于不同的场景。以下是它们的详细对比&#xff1a; — 1. 基本概念 SPI&#xff0…

SQL Server安装流程

SQL Server 2022在安全性、可用性和性能方面不断创新&#xff0c;是现在最支持Azure的SQL Server版本。 SQL Server发展史 SQL Server的历史始于1989年&#xff0c;当时是由微软与Sybase合作的产品&#xff0c;旨在为Windows NT操作系统提供一个高性能的数据库解决方案。随着…

从零开始认识大语言模型(LLM)

“AI小美好——聚焦科技、商业、职场。前沿资讯&#xff0c;实用干货&#xff0c;邂逅更美好的自己&#xff01;” 在当今数字化时代&#xff0c;语言不仅是人类交流的工具&#xff0c;更是信息传递的核心。随着人工智能技术的飞速发展&#xff0c;大语言模型逐渐走进了我们的…

安装OpenJDK21(linux、macos)

文章目录 安装OpenJDK21java21linux下安装配置mac下安装 安装OpenJDK21 java21 封神&#xff01;Java 21正式发布了&#xff0c;迎来了史诗级新特性&#xff0c;堪称版本最强&#xff01;&#xff01;&#xff01; 视频链接&#xff1a;https://www.bilibili.com/video/BV1E8…

基于Java的自助多张图片合成拼接实战

目录 前言 一、图片合成需求描述 二、图片合成设计与实现 1、编程语言 2、基础数据准备 3、图片合成流程 4、图片合成实现 三、总结 前言 在当今数字化时代&#xff0c;图像处理技术在各个领域都发挥着至关重要的作用。从社交媒体到电子商务&#xff0c;从在线教育到虚拟…

计算机网络结课设计:通过思科Cisco进行中小型校园网搭建

上学期计算机网络课程的结课设计是使用思科模拟器搭建一个中小型校园网&#xff0c;当时花了几天时间查阅相关博客总算是做出来了&#xff0c;在验收后一直没管&#xff0c;在寒假想起来了简单分享一下&#xff0c;希望可以给有需求的小伙伴一些帮助 目录 一、设计要求 二、…

在npm上传属于自己的包

最近在整理代码&#xff0c;上传到npm方便使用&#xff0c;所以学习了如何在npm发布一个包&#xff0c;整理写成一篇文章和大家一起交流。 1、注册npm账号 npm | Home 2、确保是登录状态 &#xff08;在包目录下&#xff0c;终端执行 npm login) 按enter键自动打开页面&…

物联网(IoT)详解

物联网&#xff08;IoT&#xff09;详解 1. IoT定义简介2. IoT工作原理3. IoT关键技术4. 物联网与互联网区别5. IoT使用场景6. 开源物联网平台7. 参考资料 1. IoT定义简介 首先第一个问题&#xff0c;什么是物联网&#xff08;IoT&#xff09;? 物联网&#xff08;英文&#…

idea项目列表不出现,展示loading

2025年02月08 11:23:36 星期六 发生在webstorm中&#xff0c;跟其他idea类似 原因是将 ignore 插件升级到 4.5.5 版本 https://github.com/JetBrains/idea-gitignore/pull/933 解决方案&#xff1a;将ignore版本将为 4.5.4 我是将 4.5.5 降低为 4.5.4 正常显示文件夹了。