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

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左旋。

具体代码

// 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPT每预测一个token就要调用一次模型

问题&#xff1a;下图调用了多少次模型&#xff1f; 不久以前我以为是调用一次 通过看代码是输出多少个token就调用多少次&#xff0c;如图所示&#xff1a; 我理解为分类模型 预测下一个token可以理解为分类模型&#xff0c;类别是vocab的所有token&#xff0c;每一次调用都…

Description:An attempt was made to call a method that does not exist.

错误信息 Description: An attempt was made to call a method that does not exist. The attempt was made from the following location: okio.Segment.writeTo(Segment.kt:169) The following method did not exist: kotlin.collections.ArraysKt.copyInto([B[BIII)[B T…

多行文本(多行字符串)中,如果每行文本前都有空格,各行文本前空格数最小为n,则删除每行文本前的n个空格。textwrap.dedent(多行字符串)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 多行文本(多行字符串)中&#xff0c; 如果每行文本前都有空格&#xff0c; 各行文本前空格数最小为n&#xff0c; 则删除每行文本前的n个空格。 textwrap.dedent(多行字符串) 请问以下代…

ES的安装和RestClient的操作

目录 初识elasticsearch 什么是elasticsearch elasticsearch的发展 Lucene的优缺点 elasticsearch的优势 倒排索引 es与mysql的概念对比 文档 索引 概念对比 架构 安装es 安装kibana 安装ik分词器 分词器 安装ik分词器 ik分词器的拓展和停用词典 操作索引库…

c语言中数据结构

一、结构体的由来 1. 数据类型的不足 C语言中&#xff0c;基本数据类型只有整型、字符型、浮点型等少数几种&#xff0c;无法满足复杂数据类型的需要。 2. 数组的限制 虽然数组可以存储多个同类型的数据&#xff0c;但是数组中的元素个数是固定的&#xff0c;无法动态地改变…

Unity VR Pico apk安装失败:INSTALL_FAILED_UPDATE_INCOMPATIBLE

我的报错&#xff1a; PICO4企业版。安装apk&#xff0c;报错“安装失败。&#xff08;所属的Unity项目打包的apk&#xff0c;被我在同一台pico4安装了20次&#xff09; 调试方法&#xff1a; PIco4发布使用UNITY开发的Vr应用&#xff0c;格式为apk&#xff0c;安装的时候发生…

SQL手工注入漏洞测试(MySQL数据库)

一、实验平台 https://www.mozhe.cn/bug/detail/elRHc1BCd2VIckQxbjduMG9BVCtkZz09bW96aGUmozhe 二、实验目标 获取到网站的KEY&#xff0c;并提交完成靶场。 三、实验步骤 ①、启动靶机&#xff0c;进行访问查找可能存在注入的页面 ②、通过测试判断注入点的位置(id) (1)…

嵌入式-stm32-用PWM点亮LED实现呼吸灯

一&#xff1a;知识前置 1.1、LED灯怎么才能亮&#xff1f; 答&#xff1a;LED需要低电平才能亮&#xff0c;高电平是灯灭。 1.2、LED灯为什么可以越来越亮&#xff0c;越来越暗&#xff1f; 答&#xff1a;这是用到不同占空比来实现的&#xff0c;控制LED实现呼吸灯&…

matlab时间转换

采集的GNSS数据是10hz的。 data&#xff08;选取其中一部分&#xff09;如下&#xff1a; &#xff08;1&#xff09;char类型 formatOut yyyy-mm-dd HH:MM:SS; str datestr(data,formatOut); str如下&#xff1a; &#xff08;2&#xff09;double类型 DateVector dat…

STM32独立看门狗

时钟频率 40KHZ 看门狗简介 STM32F10xxx 内置两个看门狗&#xff0c;提供了更高的安全性、时间的精确性和使用的灵活性。两个看 门狗设备 ( 独立看门狗和窗口看门狗 ) 可用来检测和解决由软件错误引起的故障&#xff1b;当计数器达到给 定的超时值时&#xff0c;触发一个中…

WU反走样算法

WU反走样算法 由离散量表示连续量而引起的失真称为走样&#xff0c;用于减轻走样现象的技术成为反走样&#xff0c;游戏中称为抗锯齿。走样是连续图形离散为想想点后引起的失真&#xff0c;真实像素面积不为 零。走样是光栅扫描显示器的一种固有现象&#xff0c;只能减轻&…

Drogon Win11 编译 /MT

Drogon是一个基于C17/20的Http应用框架&#xff0c;使用Drogon可以方便的使用C构建各种类型的Web应用服务端程序。 Drogon的主要应用平台是Linux&#xff0c;也支持Mac OS、FreeBSD和Windows。 它的主要特点如下&#xff1a; 网络层使用基于epoll(macOS/FreeBSD下是kqueue)的…

nginx反向代理服务器及负载均衡服务配置

一、正向代理与反向代理 正向代理&#xff1a;是一个位于客户端和原始服务器(oricin server)之间的服务器&#xff0c;为了从原始服务器取得内容&#xff0c;客户端向代理发送一个请求并指定目标(原始服务器)&#xff0c;然后代理向原始服务器转交请求并将获得的内容返回给客户…

Matlab/Simulink的一些功能用法笔记(3)

01--引言 最近加入到一个项目组&#xff0c;有一些测试需要去支持&#xff0c;通过了解原先团队的测试方法后&#xff0c;自己作了如下改善&#xff0c;大大提高了工作效率。这也许就是软件开发的意义吧&#xff0c;能够去除一些重复的机械的人工操作并且结果还非常不可靠。 …

Discrete Time Signals and Systems

Discrete Time Signals and Systems 文章目录 Discrete Time Signals and SystemsSignal classificationbasic signalOperation on signalSystem of discrete signalLinear systems and nonlinear systemsCausal and non-causal SystemsTime-varying and time-invariant system…

助力打造清洁环境,基于美团最新YOLOv6-4.0开发构建公共场景下垃圾堆放垃圾桶溢出检测识别系统

公共社区环境生活垃圾基本上是我们每个人每天几乎都无法避免的一个问题&#xff0c;公共环境下垃圾投放点都会有固定的值班时间&#xff0c;但是考虑到实际扔垃圾的无规律性&#xff0c;往往会出现在无人值守的时段内垃圾堆放垃圾桶溢出等问题&#xff0c;有些容易扩散的垃圾比…

使用travelbook架设自己的实时位置共享服务

travelbook 是一款开源的安卓APP&#xff0c;它能以低功耗提供实时位置共享&#xff0c;它包含功能如下&#xff1a; 好友之间分享实时位置&#xff1b;记录行程轨迹&#xff1b;标记收藏地点&#xff1b; 这款软件的主要解决的问题包括&#xff1a; 场景1&#xff1a;查看老…

【开源】基于Vue+SpringBoot的新能源电池回收系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户档案模块2.2 电池品类模块2.3 回收机构模块2.4 电池订单模块2.5 客服咨询模块 三、系统设计3.1 用例设计3.2 业务流程设计3.3 E-R 图设计 四、系统展示五、核心代码5.1 增改电池类型5.2 查询电池品类5.3 查询电池回…

安防视频云平台/可视化监控云平台EasyCVR如何快速定位占用大量存储空间的文件?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

【Vue2+3入门到实战】(4)Vue基础之指令修饰符 、v-bind对样式增强的操作、v-model应用于其他表单元素 详细示例

目录 一、今日学习目标1.指令补充 二、指令修饰符1.什么是指令修饰符&#xff1f;2.按键修饰符3.v-model修饰符4.事件修饰符 三、v-bind对样式控制的增强-操作class1.语法&#xff1a;2.对象语法3.数组语法4.代码练习 四、京东秒杀-tab栏切换导航高亮1.需求&#xff1a;2.准备代…