AVL树的模拟实现(插入,验证)

目录

前言

AVL树的概念

AVL树的旋转

旋转

左旋

右旋

左右旋

右左旋

AVL的insert的实现

AVL的验证

完整代码

总结


前言

本文会先将AVL树的旋转进行讲解, 然后再对代码进行实现和展示。 

AVL树的概念

首先 AVL树 是一种平衡树, 平衡树是在二叉搜索树的基础上进行平衡 , AVL树是一种严格平衡(即 左右子树的高度差 不超过1)。 既然AVL树是在二叉搜索树的基础进行平衡的,因此AVL树也具备二叉搜索树的基本功能。

AVL树的旋转

我们用一个 平衡因子 _bf 对AVL树进行维护。平衡因子_bf 存储 左右子树的高度差。 此文以 _bf = 左子树高度 - 右子树高度    为基准。

旋转

什么时候进行旋转? 当插入数据时, 可能进行旋转。 我们记 dest 为 要插入节点的位置, parent为dest节点的父节点。 而AVL树插入数据前具体有三种情况,如下图.

显然, 当在图【2】插入数据时,是必定不会旋转的。 而在图【1】的 3 ,4 位置, 以及图【3】的1,2位置插入数据时,也是必定不会旋转的

左旋

当在图【3】的 4 位置 插入会进左旋。 

左旋的流程:

代码实现

void RotateL(Node* parent)
{Node* pparent = parent->_parent;Node* Rchild = parent->_right;Node* RLchild = Rchild->_left;if(RLchild != nullptr)RLchild->_parent = parent;parent->_right = RLchild;Rchild->_parent = pparent;if (pparent != nullptr){if (parent == pparent->_left) pparent->_left = Rchild;else pparent->_right = Rchild;}else{_root = Rchild;}Rchild->_left = parent;parent->_parent = Rchild;Rchild->_bf = parent->_bf = 0;}
右旋

在图【1】的1位置插入 会进行右旋

右旋的流程:

代码实现:

void RotateR(Node* parent)
{Node* pparent = parent->_parent;Node* Lchild = parent->_left;Node* LRchild = Lchild->_right;if(LRchild != nullptr) LRchild->_parent = parent;parent->_left = LRchild;Lchild->_parent = pparent;if (pparent != nullptr){if (parent == pparent->_left) pparent->_left = Lchild;else pparent->_right = Lchild;}else{_root = Lchild;}parent->_parent = Lchild;Lchild->_right = parent;parent->_bf = Lchild->_bf = 0;
}
左右旋

在图【1】的2位置插入,需要左右旋。

将图【1】的2位置进行展开,如下图。

左右旋的流程

void RotateLR(Node* parent)
{Node* Lchild = parent->_left;Node* LRchild = Lchild->_right;RotateL(Lchild);RotateR(parent);if (LRchild->_bf == -1){parent->_bf = 1;Lchild->_bf = LRchild->_bf = 0;}else{Lchild->_bf = -1;LRchild->_bf = parent->_bf = 0;}
}
右左旋

在图【3】的3位置进行插入,进行右左旋

对图【3】的3位置进行展开

右左旋转流程:

代码实现:

	void RotateRL(Node* parent){Node* Rchild = parent->_right;Node* RLchild = Rchild->_left;RotateR(Rchild);RotateL(parent);if (RLchild->_bf == -1){RLchild->_bf = parent->_bf = 0;Rchild->_bf = 1;}else{parent->_bf = -1;RLchild = Rchild = 0;}}

AVL的insert的实现

插入成功返回true,插入失败返回false

bool insert(const T& x)
{if (_root == nullptr){_root = new Node(x);return true;}Node* node = _root;Node* parent = nullptr;while (node){if (x < node->_val){parent = node;node = node->_left;}else if (x > node->_val){parent = node;node = node->_right;}else{return false;}}Node* child = new Node(x);if (x < parent->_val){parent->_left = child;child->_parent = parent;parent->_bf--;}else{parent->_right = child;child->_parent = parent;parent->_bf++;}while (parent){if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){child = parent;parent = child->_parent;if (parent != nullptr){if (child == parent->_left) parent->_bf--;else parent->_bf++;}}else if (parent->_bf == 2 && child->_bf == 1){//左单旋RotateL(parent);}else if (parent->_bf == -2 && child->_bf == -1){//右单旋RotateR(parent);}else if (parent->_bf == 2 && child->_bf == -1){//右左双旋RotateRL(parent);}else if (parent->_bf == -2 && child->_bf == 1){//左右双旋转RotateLR(parent);}}return true;}

AVL的验证

	void IsAVLTree(){if (IsAVLTree(_root)) cout << "是AVL树" << endl;else cout << "不是AVL树" << endl;}
private:int GetHeight(Node* root){if (root == nullptr) return 0;int L = GetHeight(root->_left);int R = GetHeight(root->_right);return L > R ? L + 1 : R + 1;}bool IsAVLTree(Node* root){if (root == nullptr) return true;int L_Height = GetHeight(root->_left);int R_Height = GetHeight(root->_right);if (abs(L_Height - R_Height) > 1) return false;return IsAVLTree(root->_left) && IsAVLTree(root->_right);}

完整代码

template<class T>
struct Node
{T _val;Node<T>* _left;Node<T>* _right;Node<T>* _parent;int _bf = 0;Node(const T& x = T()): _val(x), _left(nullptr),_right(nullptr),_parent(nullptr){}
};template<class T>
class AVLTree
{typedef Node<T> Node;
private:Node* _root = nullptr;
public:bool insert(const T& x){if (_root == nullptr){_root = new Node(x);return true;}Node* node = _root;Node* parent = nullptr;while (node){if (x < node->_val){parent = node;node = node->_left;}else if (x > node->_val){parent = node;node = node->_right;}else{return false;}}Node* child = new Node(x);if (x < parent->_val){parent->_left = child;child->_parent = parent;parent->_bf--;}else{parent->_right = child;child->_parent = parent;parent->_bf++;}while (parent){if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){child = parent;parent = child->_parent;if (parent != nullptr){if (child == parent->_left) parent->_bf--;else parent->_bf++;}}else if (parent->_bf == 2 && child->_bf == 1){//左单旋RotateL(parent);}else if (parent->_bf == -2 && child->_bf == -1){//右单旋RotateR(parent);}else if (parent->_bf == 2 && child->_bf == -1){//右左双旋RotateRL(parent);}else if (parent->_bf == -2 && child->_bf == 1){//左右双旋转RotateLR(parent);}}return true;}void Order(){Order(_root);cout << endl;}void IsAVLTree(){if (IsAVLTree(_root)) cout << "是AVL树" << endl;else cout << "不是AVL树" << endl;}
private:int GetHeight(Node* root){if (root == nullptr) return 0;int L = GetHeight(root->_left);int R = GetHeight(root->_right);return L > R ? L + 1 : R + 1;}bool IsAVLTree(Node* root){if (root == nullptr) return true;int L_Height = GetHeight(root->_left);int R_Height = GetHeight(root->_right);if (abs(L_Height - R_Height) > 1) return false;return IsAVLTree(root->_left) && IsAVLTree(root->_right);}void Order(Node* root){if (root == nullptr) return;Order(root->_left);cout << root->_val << ' ';Order(root->_right);}void RotateL(Node* parent){Node* pparent = parent->_parent;Node* Rchild = parent->_right;Node* RLchild = Rchild->_left;if(RLchild != nullptr)RLchild->_parent = parent;parent->_right = RLchild;Rchild->_parent = pparent;if (pparent != nullptr){if (parent == pparent->_left) pparent->_left = Rchild;else pparent->_right = Rchild;}else{_root = Rchild;}Rchild->_left = parent;parent->_parent = Rchild;Rchild->_bf = parent->_bf = 0;}void RotateR(Node* parent){Node* pparent = parent->_parent;Node* Lchild = parent->_left;Node* LRchild = Lchild->_right;if(LRchild != nullptr) LRchild->_parent = parent;parent->_left = LRchild;Lchild->_parent = pparent;if (pparent != nullptr){if (parent == pparent->_left) pparent->_left = Lchild;else pparent->_right = Lchild;}else{_root = Lchild;}parent->_parent = Lchild;Lchild->_right = parent;parent->_bf = Lchild->_bf = 0;}void RotateRL(Node* parent){Node* Rchild = parent->_right;Node* RLchild = Rchild->_left;RotateR(Rchild);RotateL(parent);if (RLchild->_bf == -1){RLchild->_bf = parent->_bf = 0;Rchild->_bf = 1;}else{parent->_bf = -1;RLchild = Rchild = 0;}}void RotateLR(Node* parent){Node* Lchild = parent->_left;Node* LRchild = Lchild->_right;RotateL(Lchild);RotateR(parent);if (LRchild->_bf == -1){parent->_bf = 1;Lchild->_bf = LRchild->_bf = 0;}else{Lchild->_bf = -1;LRchild->_bf = parent->_bf = 0;}}
};

总结

实际上AVL树的实现的难点在于 AVL树旋转,搞明白旋转,剩下的就明了了

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

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

相关文章

特斯拉的底牌

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【每日一题】LeetCode 98.验证二叉搜索树(树、深度优先搜索、二叉搜索树、二叉树)

【每日一题】LeetCode 98.验证二叉搜索树&#xff08;树、深度优先搜索、二叉搜索树、二叉树&#xff09; 题目描述 给定一个二叉树的根节点 root&#xff0c;判断该二叉树是否是一个有效的二叉搜索树&#xff08;BST&#xff09;。有效的二叉搜索树需要满足以下条件&#xf…

TCP 拥塞控制:一场网络数据的交通故事

从前有条“高速公路”&#xff0c;我们叫它互联网&#xff0c;而这条公路上的车辆&#xff0c;则是数据包。你可以把 TCP&#xff08;传输控制协议&#xff09;想象成一位交通警察&#xff0c;负责管理这些车辆的行驶速度&#xff0c;以防止交通堵塞——也就是网络拥塞。 第一…

Modbus-RTU之C语言实现

Modbus-RTU之C语言实现 Modbus-RTU之C语言实现引言Modbus-RTU的C语言实现说明.h 文件.c 文件 总结 Modbus-RTU之C语言实现 引言 前面我们介绍过Modbus-RTU传输协议&#xff08;RS-485软件层协议之Modbus-RTU&#xff09;&#xff0c;它是一种基于串口的通信协议。在这一节我们…

ssl 协议工作过程

ssl 协议工作过程 ChatGPT 说&#xff1a; ChatGPT SSL&#xff08;Secure Sockets Layer&#xff09;协议是用来确保网络通信安全的加密协议&#xff0c;已被TLS&#xff08;Transport Layer Security&#xff09;取代&#xff0c;但它的工作过程仍然是理解现代加密协议的重…

MySQL索引优化与B+树【后端 14】

MySQL索引优化与B树 在MySQL数据库中&#xff0c;索引是优化查询性能的关键技术之一。B树作为一种广泛使用的索引结构&#xff0c;在MySQL的InnoDB存储引擎中扮演着核心角色。本文将详细介绍B树的结构特点及其在MySQL索引优化中的应用。 B树的结构特点 B树是B-树的一个变体&a…

uni-app怎么使用uni-icons

首先在官网&#xff08;uni-icons 图标 | uni-app官网&#xff09;中找到下载地址 uni-icons 图标 - DCloud 插件市场 把这个插件下载下来。目录结构是这样的。我们找到uni_modules 把里面的uni-icons粘贴到自己的项目中 我是放在了我的components下面了 然后再页面中引用这个…

搜索功能技术方案

1. 背景与需求分析 门户平台需要实现对服务信息的高效查询&#xff0c;包括通过关键字搜索服务以及基于地理位置进行服务搜索。面对未来可能的数据增长和性能需求&#xff0c;选择使用 Elasticsearch 来替代 MySQL 的全文检索功能。这一选择的背景与需求可以总结为以下几点&am…

Rust程序结构与代码注释

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust编程与项目实战_夏天又到了的博客-CSDN博客 3.1 Rust程序结构 我们从一个最简单的程序入手&#xff0c;来观察一个Rust的程序结…

关于前端知识中框架概念部分的详细介绍

1、为什么要学习流行框架&#xff1f; 企业&#xff1a;为了提高效率&#xff0c;因为时间就是金钱。开发人员&#xff1a;提高了开发效率发展进程&#xff1a; JS>JQuery>模板引擎>框架时代&#xff08;Angular(2)、React、Vue&#xff09;好处&#xff1a;不用直接…

揭秘蛇形机器人的主动SLAM算法和障碍物避让策略

更多优质内容&#xff0c;请关注公众号&#xff1a;智驾机器人技术前线 1.论文信息 论文标题&#xff1a;An active SLAM with multi-sensor fusion for snake robots based on deep reinforcement learning 作者&#xff1a;Xin Liu, Shuhuan Wen, Yaohua Hu, Fei Han, Hong…

文件IO编程

文章目录 文件描述符相关系统调用文件有关的系统调用文件操作函数--creat函数文件操作函数--open函数文件操作函数--read函数文件操作函数--write函数文件操作函数--close函数文件操作函数--lseek函数缓冲区的大小对性能的影响 实验&#xff1a;调用系统函数&#xff0c;实现文…

STM32 WDG看门狗

在大型项目中&#xff0c;BUG根本无法避免&#xff0c;因为可能的状态太多了&#xff0c;总有那么意想不到的情况发生&#xff0c; 所以&#xff0c;对于程序员&#xff0c;第一要要丰富的经验&#xff0c;避免一些常见的bug&#xff0c; 第二&#xff0c;程序要经常迭代&#…

集成学习(Ensembling Learning)

0. 来源 概念比较全&#xff0c;可以作为目录&#xff0c;前置知识讲得好&#xff0c;其他一般。 01.内容简介_哔哩哔哩_bilibili01.内容简介是集成学习&#xff1a;XGBoost, lightGBM的第1集视频&#xff0c;该合集共计19集&#xff0c;视频收藏或关注UP主&#xff0c;及时了…

【数据结构】排序算法系列——序言(附源码+图解)

作为基础算法的中流砥柱部分&#xff0c;排序算法一直都是计算机学习者们不可忽略的一部分。而其中的算法思想也蕴含着许多在今后的算法学习甚至是整个计算机技术的学习之中仍然熠熠生辉的算法思想&#xff0c;它们引领着我们不断探索算法的奥秘之处。所以&#xff0c;学习排序…

简单聊聊bait文件

场景&#xff1a;业务同事发现某云主机部署了企业主机安全&#xff0c;在该主机上发现了一个诱饵文件&#xff0c;显示注意&#xff1a;此文件是诱饵文件&#xff0c;用于防止重要文件被病毒加密。请勿修改或删除此文件。 解决方法&#xff1a;联系企业主机安全运维同事发现&am…

信号保存和处理

把上一篇回顾一下吧&#xff1a;共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间&#xff0c;这些进程间数据传递不再涉及到内核&#xff0c;进程不再通过执行进入内核的系统调用来传递彼此的数据 共享内存的数据结构&#xff1a; struct shmid_ds {…

QT实现TCP/UDP通信

服务器端&#xff1a; 客户端&#xff1a; 服务器&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QList> #include <QMessageBox> #include <QDebug&…

point transformer v3复现及核心代码详解

point transformer v3复现及核心代码详解 1. 复现1.1 复现1.2 数据预处理1.3 跑通 2. 核心代码详解2.1 读取数据2.2 dataloder2.3 模型读取数据的逻辑2.4 forward2.4.1 Point2.4.2 backbone2.4.2.1 point.serialization2.4.2.2 稀疏化2.4.2.3 embedding2.4.2.4 encoder 1. 复现…

Emlog程序屏蔽用户IP拉黑名单插件

插件介绍 在很多时候我们需要得到用户的真实IP地址&#xff0c;例如&#xff0c;日志记录&#xff0c;地理定位&#xff0c;将用户信息&#xff0c;网站数据分析等,其实获取IP地址很简单&#xff0c;感兴趣的可以参考一下。 今天给大家带来舍力写的emlog插件&#xff1a;屏蔽…