AVL树的实现

概念

1.为了解决二叉搜索树有序插入,会退化成链表,导致效率低下。

AVL树的左右子树高度差不超过1,所以AVL树的查找效率为logn。

2.在左子树高度增加,平衡因子减一,在右子树高度增加,平衡因子加一。

节点的定义

template<class key, class value>struct TreeNode{typedef TreeNode Node;TreeNode< key, value>* left;TreeNode< key, value>* right;TreeNode< key, value>* _parent;std::pair <key, value> data;int bf;//平衡因子TreeNode(const std::pair<key, value>& kv = kv()):left(nullptr), right(nullptr), _parent(nullptr), data(kv), bf(0){}};

插入

这种情况是最简单的情况,只需找到插入位置即可,

当插入节点小于当前节点,那么去左子树找插入位置。

插入节点大于当前节点,那么去右子树寻找插入位置。

当前节点为空时,就是插入位置。

调平衡因子

1.插入之后树高度不变

这种情况插入只会影响父亲,不会影响祖先。

所以只需要修改父亲的平衡因子。

2.插入之后,高度增加

这种情况,树的高度增加,会影响整棵树的平衡因子,需要一直向上调整,直到当前节点为根节点。

旋转

在向上调节平衡因子的时候,发现|bf| > 1 ,进行旋转。

1.父亲和孩子在一条直线上

调节到黑色节点时bf == -2,进行右旋转,bf == 2 ,进行左旋转。

将橙色节点,连入黑色的左节点

黑色节点变为红色的右节点

红色在与黑色的父亲节点连接,没有父亲父亲节点变为nullptr

将黑色节点,和红色节点的平衡因子置为0。

2.父亲和孩子不在同一条直线上

如果只进行一次右旋还是会不平平衡。

调节到黑色节点时bf == -2,进行左右双旋转,bf == 2 ,进行右左双旋转。

先对红色节点进行一次左旋

在对黑色节点进行一次右旋

最后调平衡因子分三种情况

经过上图发现,橙色的左节点,变成了红色的右节点。

橙色的右节点,变成黑色的左节点。

1.当橙色的bf == -1

红 bf = 0

黑 bf = 1

橙 bf = 0

2.当橙色bf == 1

红 bf = -1

黑 bf = 0

橙 bf = 0

3.当橙色bf == 0 说明橙是新插入节点

红 bf = 0

黑 bf = 0

橙 bf = 0

完整代码

#pragma once
#include<iostream>
#include<assert.h>namespace AVL
{template<class key, class value>struct TreeNode{typedef TreeNode Node;TreeNode< key, value>* left;TreeNode< key, value>* right;TreeNode< key, value>* _parent;std::pair <key, value> data;int bf;TreeNode(const std::pair<key, value>& kv = kv()):left(nullptr), right(nullptr), _parent(nullptr), data(kv), bf(0){}};template<class key, class value>class AVLTree{typedef TreeNode<key, value> Node;public:bool insert(std::pair< key, value> p){Node* cur = _root;if (cur == nullptr){_root = new Node(p);return true;}Node* parent = nullptr;while (cur){if (cur->data.first > p.first){parent = cur;cur = cur->left;}else if (cur->data.first < p.first){parent = cur;cur = cur->right;}else if (cur->data.first == p.first){return false;}}//bf 左负 右正cur = new Node(p);if (p.first < parent->data.first){parent->left = cur;}else{parent->right = cur;}cur->_parent = parent;//parent 的左右都不为空,只影响父亲//parent的左右有一个为空,影响祖先while (parent){if (cur == parent->left){parent->bf--;}else{parent->bf++;}if (parent->bf == 0){break;}else if (parent->bf == -1 || parent->bf == 1){cur = 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 if ((parent->bf == -2 )&& (cur->bf == 1))//左右双旋{RotateLR(parent);}break;}}return true;}void inorder(){_inorder(_root);}void RotateL(Node* parent){Node* subR = parent->right;Node* subRL = subR->left;Node* ppNode = parent->_parent;subR->left = parent;parent->_parent = subR;parent->right = subRL;if(subRL != nullptr){subRL->_parent = parent;}if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (parent == ppNode->left){ppNode->left = subR;}else{ppNode->right = subR;}subR->_parent = ppNode;}subR->bf = 0;parent->bf = 0;}void RotateR(Node* parent){Node* subL = parent->left;Node* subLR = subL->right;Node* ppNode = parent->_parent;subL->right = parent;parent->_parent = subL;parent->left = subLR;if(subLR != nullptr){subLR->_parent = parent;}if (parent == _root){_root = subL;subL->_parent = nullptr;}else{if (parent == ppNode->left){ppNode->left = subL;}else{ppNode->right = subL;}subL->_parent = ppNode;}parent->bf = 0;subL->bf = 0;}void RotateRL(Node *parent){Node* subR = parent->right;Node* subRL = subR->left;int bf = subRL->bf;RotateR(parent->right);RotateL(parent);subRL->bf = 0;//RL的右给R的左  左子树给P的右if (bf == 1){subR->bf = 0;parent->bf = -1;}else if (bf == -1){subR->bf = 1;parent->bf = 0;}else if(bf == 0){subR->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);subLR->bf = 0;if (bf == 1){parent->bf = 0;subL->bf = -1;}else if (bf == -1){parent->bf = 1;subL->bf = 0;}else if(bf == 0){parent->bf = 0;subL->bf = 0;}else{assert(false);}}bool check(){int height = 0;return _check(_root,height);}private:Node* _root = nullptr;bool _check(Node* root,int &height){if (root == nullptr){height == 0;return true;}//检查左右子树高度差是否为1int leftheight = 0, rightheight = 0;if (!_check(root->left, leftheight) || ! _check(root->right, rightheight)){return false;}if (abs(rightheight - leftheight) >= 2){std::cout << "高度错误" << std::endl;return false;}if (rightheight - leftheight != root->bf){std::cout << "平衡因子错误" << std::endl;return false;}height = leftheight > rightheight ? leftheight+1 : rightheight+1;return true;}void _inorder(Node* root){if (root == nullptr){return;}_inorder(root->left);std::cout << "key:" << root->data.first << " " << "bf:" << root->bf << std::endl;check();			_inorder(root->right);}};}

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

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

相关文章

C# winform修改背景图 控件双向绑定 拖拽打开图片

修改背景图 说明 这里我准备基于百度飞桨PaddleSeg项目的人像分割模块做一个人像抠图&#xff0c;这里顺便用上了双向绑定和图片拖拽打开。 下面就是示例&#xff1a; 用颜色替换 用背景图替换 保存成功后的图片 一、使用百度飞桨PaddleSeg //初始化 引擎engine new Padd…

如何配置VS Code环境

一、下载 Visual Studio Code - Code Editing. Redefined 二、傻瓜式安装 如果出现没有安装路径选择&#xff0c;则看下面图片 经过上面操作后&#xff0c;可以修改路径 三、按照下面步骤配置环境变量即可 Visual Studio Code 中的 C 和 MinGW-w64 入门

数据库学习之数据库基本知识

什么是数据库 数据&#xff1a;描述事物地符号记录&#xff0c;包括单不限于数字、文字、图形、图像、声音、语言等。数据有多种形式&#xff0c;这个内容都可以经过式子化地处理后存入计算机。 数据库&#xff1a;数据仓库。是长期存放再计算机内、有组织、可共享地大量数据…

UE5 C++增强输入

一.创建charactor&#xff0c;并且包含增强输入相关的头文件 1.项目名.build.cs。添加模块“EnhancedInput”&#xff0c;方便找到头文件和映射的一些文件。 PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine&q…

在基于Android相机预览的CV应用程序中使用 OpenCL

查看&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV4.9.0在Android 开发简介 下一篇&#xff1a;在 MacOS 中安装 本指南旨在帮助您在基于 Android 相机预览的 CV 应用程序中使用 OpenCL ™。教程是为 Android Studio 20…

用图解说明mysql 行锁加锁规则

加锁原则 原则 1&#xff1a;加锁的基本单位是 next-key lock。希望你还记得&#xff0c;next-key lock 是前开后闭区间。原则 2&#xff1a;查找过程中访问到的对象才会加锁。优化 1&#xff1a;索引上的等值查询&#xff0c;给唯一索引加锁的时候&#xff0c;next-key lock …

【Java】Oracle发布Java22最新版本

甲骨文&#xff08;ORACLE&#xff09;已经于2023年3月19日正式发布了最新版本的JDK&#xff0c;版本号&#xff1a;22 根据官方声明&#xff0c;Java 22 (Oracle JDK 22) 在性能、稳定性和安全性方面进行了数千种改进&#xff0c;包括对Java 语言、其API 和性能&#xff0c;以…

python vtk读取vtk文件

参考&#xff1a; https://cloud.tencent.com/developer/ask/sof/101993637 方法一&#xff1a;使用pyvtk 要使用Python读取VTK文件&#xff0c;可以使用pyvtk库。首先&#xff0c;确保已经安装了pyvtk。如果没有安装&#xff0c;可以通过pip安装&#xff1a; csharp pip ins…

Github基本功能和使用技巧

基础功能 创建仓库&#xff08;Repository&#xff09;&#xff1a;在GitHub上创建一个新的仓库&#xff0c;可以通过点击页面右上角的“New”按钮开始。选择仓库的名称、描述和许可证等信息&#xff0c;并选择是否将仓库设置为公开或私有。 克隆仓库&#xff08;Clone&#x…

基于stable diffusion的IP海报生成

【AIGC】只要10秒&#xff0c;AI生成IP海报&#xff0c;解放双手&#xff01;&#xff01;&#xff01;在AIGC市场发展的趋势下&#xff0c;如何帮助设计工作者解放双手。本文将从图像生成方向切入&#xff0c;帮助大家体系化的学习Stable diffusion的使用&#xff0c;完成自有…

php 对接IronSource海外广告平台收益接口Reporting API

今天对接的是IronSource广告reporting api接口&#xff0c;拉取广告收益回来自己做统计。记录分享给大家 首先是文档地址,进入到IronSource后台就能看到文档地址以及参数&#xff1a; 文档地址&#xff1a;https://developers.is.com/ironsource-mobile/air/reporting/ 在这里插…

【Rust】——String集合

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

高新技术企业培育认定条件

高新技术企业认定申报条件主要包括企业基本条件、技术创新能力和成果、知识产权、人才队伍建设等方面。 1.企业基本条件 &#xff08;1&#xff09;具有独立法人资格&#xff1b; &#xff08;2&#xff09;注册地在中国境内&#xff1b; &#xff08;3&#xff09;注册资本…

Mybatis一级缓存和二级缓存区别

Mybatis一级缓存 1.为什么需要Mybatis一级缓存 当我们使用Mybatis进行数据库的操作时候&#xff0c;会创建一个SqlSession来进行一次数据库的会话&#xff0c;会话结束则关闭SqlSession对象。 如果我们很有可能多次查询完全相同的sql语句&#xff0c;每一次查询都查询一次数据…

基于Python3的数据结构与算法 - 16 链表

目录 链表 1. 创建链表 2. 链表的插入和删除 3. 双链表 4. 链表总结 链表 链表是由一系列节点组成的元素集合。每个节点包含两部分&#xff0c;数据域item和指向下一个节点得指针next。通过节点之间的相互连接&#xff0c;最终串联成一个链表。 class Node:def __init…

如何利用人工智能技术实现企业营销效率提升10倍(上)

01. 品牌营销面临越来越大的挑战 在当前行业下行周期&#xff0c;品牌营销正面临着前所未有的挑战。首当其冲的是高昂的营销费用&#xff0c;这使得企业在投入资源时更加谨慎&#xff0c;同时也需要寻求更加高效的营销手段来确保投入产出比的最大化。其次&#xff0c;由于缺乏…

Linux系统本地部署Docker Compose UI服务结合内网穿透实现公网访问

文章目录 1. 安装Docker2. 检查本地docker环境3. 安装cpolar内网穿透4. 使用固定二级子域名地址远程访问 Docker Compose UI是Docker Compose的web界面。这个项目的目标是在Docker Compose之上提供一个最小的HTTP API&#xff0c;同时保持与Docker Compose CLI的完全互操作性。…

探讨苹果 Vision Pro 的空间视频(术语辨析、关键技术、思考)

背景:一位资深视频技术从业者在 Pixvana 工作,积累了丰富的捕获、处理、编码、流传和播放空间媒体经验。 一、术语 空间视频:传统的 3D 视频,呈矩形,包含左右眼视图,如 iPhone15 Pro 和 Vision Pro 可录制。沉浸式视频:非矩形的环绕式视频体验,通常由两个或多个传感器…

Unity 学习笔记 5.控制飞机飞行

目录 1.摄像机跟随的方法 2.鼠标按键响应 3.键盘按键响应 4.导入素材 5.让飞机向前飞 6.摄像机跟随飞机移动 7.鼠标控制飞机倾斜 8.键盘控制飞机飞行 下载源码 UnityPackage 1.摄像机跟随的方法 2.鼠标按键响应 3.键盘按键响应 4.导入素材 下载素材 步骤&#xff1a; 将…

蓝桥杯 第3217题 简单的异或难题 C++ Java Python

题目 思路和解题方法 计算给定数组中子数组异或和的问题。它采用了前缀异或的方法来预处理数组&#xff0c;然后对于每个查询&#xff0c;通过异或操作计算子数组的异或和。 读取输入的数组&#xff0c;并计算每个位置的前缀异或和。对于每个查询&#xff0c;读取查询的左右边界…