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 入门

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;以…

基于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/ 在这里插…

基于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;读取查询的左右边界…

css使用变量

vue3单文件SFC新特性在css里可以使用变量&#xff0c;具体使用如下&#xff1a; <template><div class"home-view"><span>测试</span><p>测试2</p></div> </template><script setup lang"ts"> imp…

C++关键字:const

文章目录 一、const的四大作用1.修饰 变量、数组2.修饰 函数的形参、修饰 引用 (最常用&#xff09;3.修饰 指针&#xff1a;常量指针、指针常量 、只读指针4.修饰 类的成员函数、修饰 类的对象 一、const的四大作用 1.修饰 变量、数组 1.const修饰变量&#xff1a; 被const修…

基于Spring Boot的煤矿信息管理系统

摘 要 系统根据现有的管理模块进行开发和扩展&#xff0c;采用面向对象的开发的思想和结构化的开发方法对煤矿信息管理的现状进行系统调查。采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计中采用“自下而上…

一分钟了解自动化测试【建议收藏】

引子 写在最前面&#xff1a;目前自动化测试并不属于新鲜的事物&#xff0c;或者说自动化测试的各种方法论已经层出不穷&#xff0c;但是&#xff0c;能够明白自动化测试并很好落地实施的团队还不是非常多&#xff0c;我们接来下用通俗的方式来介绍自动化测试…… 本文共有2410…

Web Service接口测试

Web service 接口测试 一. web Service概念 Web service使用与平台和编程语言无关的方式进行通讯的一项技术, web service 是一个接口, 他描述了一组可以在网络上通过标准的XML消息传递访问的操作,它基于xml语言协议来描述要执行的操作或者要与另外一个web 服务交换数据, 一组…

C语言每日一题06

一、题目 二、解析 void main &#xff08;&#xff09; { char c1&#xff0c;c2&#xff1b; int a1&#xff0c;a2&#xff1b; c1 getchar &#xff08;&#xff09;&#xff1b;//读取第一个输入&#xff0c;c11 scanf &#xff08;“%3d”&#xff0c;&a1&#xff…