算法与数据结构--二叉搜索树与自平衡二叉搜索树

0.字典(即c++的map)

注:字典的 "member运算" 指的是检查字典中是否存在某个特定的键的操作,即查询操作。

如果我们使用数组来实现字典/map,虽然使用二分法查询也可以达到logn,但是的话插入和删除太慢了。使用链表实现的话虽然插入和删除是O(1),但是查询的话达到了O(n),也不可取。

因此人们发明了自平衡二叉查找树,在保证查找效率的同时,又保证了插入和删除的效率,从而更好的实现字典。

c++的map和set就是用红黑树来实现的(一种特殊的自平衡二叉搜索树)。而unorder_map使用哈希表实现的。

1.二叉查找树--BST

在讲自平衡二叉搜索树之前,我们要先明白什么是二叉搜索树。

二叉查找树(Binary Search Tree),是具有如下性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。

使用二叉搜索树进行添加,删除,搜索的平均时间复杂度都为O(logn)

2.自平衡二叉查找树--AVL树

1.为什么要有AVL树

二叉查找树虽然平均添加,删除,查找效率为O(logn),但是却不稳定,比如像上面这张图,在最坏的情况下,也就是该二叉树不平衡的时候,效率又降到了O(n)。

所以我们要想办法让这颗二叉查找树平衡,让结点平均地分布在树的两侧,从而提高算法的稳定性,于是就发明了自平衡二叉搜索树,即AVL树。

2.AVL树的定义

3.如何构建AVL树

具体流程:

元素插入二叉搜索树中->判断结点是否平衡,具体是那种情况的不平衡->根据所处的不平衡情况进行不同的调整策略

当遇到结点不平衡时:

根据插入元素的落点,调整策略分为四种情况,插入元素落入以下4个子树的情况分别对应着四种状态。

【1】右旋--LL型状态

这时候对A结点,也就是根结点使用右旋操作进行调整。A连接左子树的右子树,A称为B的右子树。

【2】左旋--RR型状态

这时候对根结点使用左旋操作。

【3】先左旋后右旋--LR型状态

采用LR双旋。

这个操作等效与先对B结点作左旋操作,再对A结点作右旋操作。

【4】先右旋后左旋--RL型状态

采用RL双旋。

RL双旋等效于先对C右旋,再对A左旋。

具体代码

gpt生成,以后有时间再自己写一遍

#include <iostream>
#include <algorithm>// AVL节点的定义
struct AVLNode {int data;AVLNode* left;AVLNode* right;int height;AVLNode(int value) : data(value), left(nullptr), right(nullptr), height(1) {}
};// 获取节点的高度
int getHeight(AVLNode* node) {if (node == nullptr)return 0;return node->height;
}// 计算平衡因子
int getBalanceFactor(AVLNode* node) {if (node == nullptr)return 0;return getHeight(node->left) - getHeight(node->right);
}// 更新节点的高度
void updateHeight(AVLNode* node) {if (node != nullptr) {node->height = 1 + std::max(getHeight(node->left), getHeight(node->right));}
}// 右旋转
AVLNode* rightRotate(AVLNode* y) {AVLNode* x = y->left;AVLNode* T2 = x->right;x->right = y;y->left = T2;updateHeight(y);updateHeight(x);return x;
}// 左旋转
AVLNode* leftRotate(AVLNode* x) {AVLNode* y = x->right;AVLNode* T2 = y->left;y->left = x;x->right = T2;updateHeight(x);updateHeight(y);return y;
}// 插入节点
AVLNode* insertNode(AVLNode* root, int key) {if (root == nullptr) {return new AVLNode(key);}if (key < root->data) {root->left = insertNode(root->left, key);} else if (key > root->data) {root->right = insertNode(root->right, key);} else {// 重复的键值不允许插入return root;}// 更新节点的高度updateHeight(root);// 获取平衡因子int balance = getBalanceFactor(root);// 进行旋转操作以保持平衡// 左子树不平衡if (balance > 1) {if (key < root->left->data) {// 左-左情况,进行右旋转return rightRotate(root);} else {// 左-右情况,先左旋转,再右旋转root->left = leftRotate(root->left);return rightRotate(root);}}// 右子树不平衡if (balance < -1) {if (key > root->right->data) {// 右-右情况,进行左旋转return leftRotate(root);} else {// 右-左情况,先右旋转,再左旋转root->right = rightRotate(root->right);return leftRotate(root);}}// 树保持平衡,直接返回根节点return root;
}// 中序遍历 AVL 树
void inOrderTraversal(AVLNode* root) {if (root != nullptr) {inOrderTraversal(root->left);std::cout << root->data << " ";inOrderTraversal(root->right);}
}int main() {AVLNode* root = nullptr;// 插入一些节点root = insertNode(root, 10);root = insertNode(root, 20);root = insertNode(root, 30);root = insertNode(root, 15);root = insertNode(root, 5);// 输出中序遍历结果std::cout << "In-order traversal of AVL tree: ";inOrderTraversal(root);std::cout << std::endl;return 0;
}

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

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

相关文章

SourceTree的安装和使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装&#xff1a;二、使用步骤1.获取地址2.放入sourceTree 3.点击推送 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 简单讲解一…

XV7001BB陀螺传感器

XV7001BB是一款工业级的高精度角度测量仪器&#xff0c;具备SPI或i2c串行接口&#xff0c;能够输出16位的角速率数据。同时&#xff0c;内置温度传感器可以实时监测环境温度&#xff0c;可选数字滤波器可以有效降低噪声干扰&#xff0c;使得测量结果更加准确可靠。作为一款低功…

Apache OFBiz 远程代码执行漏洞(CVE-2023-51467)

产品简介 Apache OFBiz是一个电子商务平台&#xff0c;用于构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类应用系统。 漏洞概述 该系统的身份验证机制存在缺陷&#xff0c;可能允许未授权用户通过绕过标准登录流程来获取后台访问权限。此外&…

Docker常用命令详细整合

超详细Docker整合笔记可看&#xff1a;尚硅谷Docker基础篇和Dockerfile超详细整合笔记-CSDN博客 ———————————————————————————— Docker常用命令&#xff1a; 帮助启动类命令&#xff1a; 启动docker&#xff1a; systemctl start docker 停止…

Visual Studio Code 中,通过显示波浪线来提示代码中存在的错误或警告

在Visual Studio Code (VSCode)中&#xff0c;编辑器会通过显示波浪线&#xff08;也称为squiggles&#xff09;来提示代码中存在的错误或警告。这些波浪线的颜色通常为红色表示错误&#xff0c;黄色表示警告。 1. 自定义错误和警告提示 • 打开设置&#xff1a;点击左上角菜单…

WebService

调试工具&#xff1a;Postman、SoapUI Soap WebService :.net WCF 、Java CFX WebService三要素&#xff1a; SOAP&#xff08;Simple Object Access Protocol&#xff09;&#xff1a;用来描述传递信息的格式&#xff0c; 可以和现存的许多因特网协议和格式结合使用&#x…

使用bat来生成mp4文件转m4s文件格式

bat设置变量 echo off set /p a请输入mp4名称(最好是在assets/video文件下存储): echo %a%bat设置utf-8编码 Chcp 65001m4s保存保存 注意: 需要下载ffmpeg并保存在系统环境变量中方可执行 echo off#设置utf-8编码 chcp 65001set /p a请输入mp4名称(最好是在assets/video文件下…

了解英语中主语谓语宾语等等句子成分

目录 官方书面解释&#xff1a; 简介&#xff1a; 细分&#xff1a; 通俗易懂解释&#xff1a; 各个成分的解释&#xff1a; 扩展资料&#xff1a; 官方书面解释&#xff1a; 简介&#xff1a; 在句子中&#xff0c;词与词之间有一定的组合关系&#xff0c;按照不同的…

三分钟学完科研论文常用统计图

统计分析的结果通常包括统计图和统计表。统计图是一种用图形表示数据的方式&#xff0c;它能够直观地展示数据的分布、趋势和关系。科研论文中常见的统计图包括条形图、饼图、折线图、散点图等。这些图形可以帮助人们快速地理解和分析数据&#xff0c;找出其中的规律和特征。今…

赛宁综合安全验证评估,筑牢关基网络安全屏障

在国际复杂态势和数字经济发展的驱动下&#xff0c;关键信息基础设施&#xff08;以下简称&#xff1a;关基&#xff09;的安全运营逐步走向实战化、体系化和常态化。验证评估作为安全运营的试金石&#xff0c;已成为实现动态防御、主动防御的有力手段。如何通过体系化验证评估…

【WPF】 使用UserControl并在XAML中赋初始值

文章目录 一、前言二、使用步骤1. cs中设置控件属性2. 在引入控件时&#xff0c;Xaml传初始值 一、前言 在XAML中使用自定义控件&#xff0c;并在XAML中并赋初始值。 二、使用步骤 1. cs中设置控件属性 设置OriginLocation&#xff0c;ScaleInterval 属性&#xff0c;可以通…

刷脸消费进入机关单位、企业员工消费应用场景

随着人脸识别技术的应用越来越广泛&#xff0c;刷卡消费已逐步被刷脸消费所替代。目前在一些高等院校、机关单位甚至是企业开始投入使用人脸消费机。与传统的刷卡识别技术相比&#xff0c;人脸识别技术具有以下优势&#xff1a; 无需持卡&#xff0c;方便人员使用。避免卡片丢…

DS18B20温度检测及其液晶显示

#include<reg51.h> //包含单片机寄存器的头文件 #include<intrins.h> //包含_nop_()函数定义的头文件 unsigned char code digit[10]{"0123456789"}; //定义字符数组显示数字 unsigned char code Str[]{"Test by DS18B20"}; //说明…

DP进阶之路——01背包问题

题目链接&#xff1a;题目页面 小明是一位科学家&#xff0c;他需要参加一场重要的国际科学大会&#xff0c;以展示自己的最新研究成果。他需要带一些研究材料&#xff0c;但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等&#xff0c;它们各自占据不…

web自动化上传文件

1&#xff0c;web 自动化文件上传不要太简单 熟悉 web 自动化测试的大佬应该都懂&#xff0c;当采用 js 调用原生控件进行文件上传的时候&#xff0c;最常用的是使用 pywin32 等系统交互库。 当看到 pywin32 那丑陋的 api 封装只能爆粗口。就为了输入一个文件地址&#xff0c;…

Python多线程和线程池的下载实战用法

1.多线程和线程池用法区别 多线程和线程池都是Python中常用的并发编程方式&#xff0c;根据具体的需求和场景选择合适的方式。 多线程&#xff1a; 优点&#xff1a;直观、简单&#xff0c;适合简单的并发任务。可以使用 threading.Thread 类创建线程&#xff0c;每个线程独立…

频谱论文:基于空间稀疏采样的频谱态势生成: 模型与算法

#频谱# 张国勇,王军,陈霄南等.基于空间稀疏采样的频谱态势生成:模型与算法[J].中国科学:信息科学,2022,52(11):2011-2036. &#xff08;电子科技大学&#xff09; 摘要 面对日益复杂的电磁频谱环境和持续增长的用频需求, 为了维护电磁频谱秩序和安全, 提高频谱资源整体利用效率…

【Vue】Vue2的最后一舞

Vue 2.7 是 Vue 2.x 的最后一个次级版本。在此发布之后&#xff0c;Vue 2 将会进入长期技术支持 (LTS&#xff1a;long-term support) 状态&#xff0c;该状态从现在起计算会持续 18 个月&#xff0c;且不再提供新特性。 根据Vue官网的说法&#xff0c;随着Vue 2.7的发布&#…

《LeetCode力扣练习》代码随想录——栈与队列(逆波兰表达式求值---Java)

《LeetCode力扣练习》代码随想录——栈与队列&#xff08;逆波兰表达式求值—Java&#xff09; 刷题思路来源于 代码随想录 150. 逆波兰表达式求值 栈 class Solution {public int evalRPN(String[] tokens) {// Stack<Integer> stacknew Stack<>();Deque<Integ…

Vue - 事件处理详解

组件代码 下面是一个基本的 Vue.js 组件代码&#xff0c;其中包含了不同类型的事件处理器&#xff1a; <template><div><!-- 内联事件处理器&#xff1a;点击按钮时调用 increaseCount 方法 --><button click"increaseCount">加 1</but…