【数据结构】AVL树

AVL树

AVL树(Adelson-Velsky和Landis树)是一种自平衡二叉搜索树。它通过维护树的高度平衡来确保树的操作复杂度为O(log n)。它通过在每个节点上跟踪平衡因子来保持树的平衡。平衡因子是左子树和右子树高度之间的差值。

AVL树的特性

  • 每个节点都有一个平衡因子。
  • 平衡因子等于左子树高度减去右子树高度。
  • 平衡因子必须为-1、0或1。
  • 当插入或删除节点后,平衡因子可能会发生改变,如果平衡因子超出了-1到1的范围,需要通过旋转操作来调整树的结构。

AVL树的操作

AVL树提供了基本的操作,包括插入、删除和查找操作。下面是这些操作的C语言实现。

定义节点结构

首先,我们定义AVL树的节点结构。节点包含一个整数值 value,指向左子树和右子树的指针 leftright,以及一个表示子树高度的字段 height

typedef struct AVLNode {int value;int height;struct AVLNode *left;struct AVLNode *right;
} AVLNode;
左旋和右旋操作

AVL树使用左旋和右旋操作来调整树的结构,确保树的平衡。

// 计算节点的高度
int height(AVLNode *node) {if (node == NULL) {return 0;}return node->height;
}// 更新节点的高度
void updateHeight(AVLNode *node) {if (node) {node->height = 1 + fmax(height(node->left), height(node->right));}
}// 左旋操作
AVLNode* leftRotate(AVLNode *z) {AVLNode *y = z->right;AVLNode *T2 = y->left;// 执行左旋y->left = z;z->right = T2;// 更新节点高度updateHeight(z);updateHeight(y);// 返回新的根节点return y;
}// 右旋操作
AVLNode* rightRotate(AVLNode *z) {AVLNode *y = z->left;AVLNode *T2 = y->right;// 执行右旋y->right = z;z->left = T2;// 更新节点高度updateHeight(z);updateHeight(y);// 返回新的根节点return y;
}

左旋操作将节点 z 的右子树调整为其父节点,右旋操作将节点 z 的左子树调整为其父节点。这些操作用于调整树的结构并保持平衡。

平衡因子计算

平衡因子是AVL树的一个重要属性。它表示节点的左子树高度减去右子树高度的差值。

int getBalance(AVLNode *node) {if (node == NULL) {return 0;}return height(node->left) - height(node->right);
}
插入操作

插入操作在AVL树中插入一个新的值,同时确保树保持平衡。插入后,需要调整树的结构以保持平衡。

// 插入操作
AVLNode* insert(AVLNode *node, int value) {// 执行标准的二叉搜索树插入操作if (node == NULL) {AVLNode *newNode = (AVLNode *)malloc(sizeof(AVLNode));newNode->value = value;newNode->height = 1;newNode->left = newNode->right = NULL;return newNode;}if (value < node->value) {node->left = insert(node->left, value);} else if (value > node->value) {node->right = insert(node->right, value);} else {// 值已存在于树中return node;}// 更新节点的高度updateHeight(node);// 获取平衡因子int balance = getBalance(node);// 根据平衡因子进行调整// 左左情况if (balance > 1 && value < node->left->value) {return rightRotate(node);}// 右右情况if (balance < -1 && value > node->right->value) {return leftRotate(node);}// 左右情况if (balance > 1 && value > node->left->value) {node->left = leftRotate(node->left);return rightRotate(node);}// 右左情况if (balance < -1 && value < node->right->value) {node->right = rightRotate(node->right);return leftRotate(node);}return node;
}

插入操作首先执行标准的二叉搜索树插入操作,将新值插入树中。然后,更新节点的高度并获取平衡因子。根据平衡因子的值,决定是否需要进行旋转操作来保持树的平衡。

删除操作

删除操作在AVL树中删除特定值,同时确保树保持平衡。删除操作可能需要多种情况处理。

// 找到最小值节点
AVLNode* minValueNode(AVLNode *node) {while (node->left != NULL) {node = node->left;}return node;
}// 删除操作
AVLNode* deleteNode(AVLNode *root, int value) {// 执行标准的二叉搜索树删除操作if (root == NULL) {return root;}if (value < root->value) {root->left = deleteNode(root->left, value);} else if (value > root->value) {root->right = deleteNode(root->right, value);} else {// 找到要删除的节点if (root->left == NULL) {AVLNode *temp = root->right;free(root);return temp;} else if (root->right == NULL) {AVLNode *temp = root->left;free(root);return temp;}// 找到右子树的最小值节点AVLNode *temp = minValueNode(root->right);// 复制最小值节点的值到当前节点root->value = temp->value;// 递归删除右子树的最小值节点root->right = deleteNode(root->right, temp->value);}// 更新节点的高度updateHeight(root);// 获取平衡因子int balance = getBalance(root);// 根据平衡因子进行调整// 左左情况if (balance > 1 && getBalance(root->left) >= 0) {return rightRotate(root);}// 左右情况if (balance > 1 && getBalance(root->left) < 0) {root->left = leftRotate(root->left);return rightRotate(root);}// 右右情况if (balance < -1 && getBalance(root->right) <= 0) {return leftRotate(root);}// 右左情况if (balance < -1 && getBalance(root->right) > 0) {root->right = rightRotate(root->right);return leftRotate(root);}return root;
}

删除操作首先执行标准的二叉搜索树删除操作。删除后,更新节点的高度并获取平衡因子。根据平衡因子的值,决定是否需要进行旋转操作来保持树的平衡。

查找操作

查找操作在AVL树中查找特定值。查找过程与二叉搜索树类似,但AVL树能够在操作后确保树的平衡。

AVLNode* search(AVLNode* node, int value) {if (node == NULL || node->value == value) {return node;}// 根据值的大小决定查找方向if (value < node->value) {return search(node->left, value);} else {return search(node->right, value);}
}

查找操作递归地遍历树,根据值的大小选择左子树或右子树进行查找。

总结

AVL树是一种自平衡二叉搜索树,通过维护树的高度平衡来确保树的操作复杂度为O(log n)。它提供了查找、插入和删除操作的对数时间复杂度,非常适合需要快速操作和高性能的数据结构。

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

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

相关文章

机器学习——模型评价

概述 在机器学习中&#xff0c;模型评价是评估和比较不同模型性能的关键步骤之一。它是通过对模型的预测结果与真实标签进行比较&#xff0c;从而量化模型的预测能力、泛化能力和稳定性。模型评价旨在选择最佳的模型&#xff0c;理解模型的行为&#xff0c;并为模型的改进提供…

Synchronized简述

1.了解Synchrozied Synchrozied是一种悲观锁&#xff0c;通过Synchroized实现同步机制&#xff0c;在操作数据时&#xff0c;判断该对象是否被锁定&#xff0c;如果被锁定则进入阻塞状态直到被占用的线程释放&#xff0c;如果没有被锁或者当前线程已经存在操作对象的锁则进行上…

大模型(LLM)与人类大脑的结构及运行机制的关系

大模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;与人类大脑的结构及运行机制之间存在一些有趣的类比和潜在的关联&#xff0c;尽管两者在本质和实现方式上存在显著差异。 首先&#xff0c;从结构上来看&#xff0c;人类大脑是一个高度复杂和互联的网络&am…

SpringBoo利用 MDC 机制过滤出单次请求相关的日志

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 1.前言 2.MDC 是什么 3.代码实战 4.总结 1.前言 在服务出现故障时&#xff…

springboot @ConditionalOnProperty注解

ConditionalOnProperty注解可以有条件的加载bean 比如有3个定时任务&#xff0c;想设置开关 1、配置中添加 config:schedule:enabled:aaaScheduler: truebbbScheduler: truecccScheduler: true 2、代码 Component ConditionalOnProperty(prefix "config.schedule.en…

【功能更新】强化知识库管理与AI问答机器人性能

三月HelpLook带来了3大类功能焕新&#xff0c;主要聚焦于&#xff1a;知识库的管理功能升级和AI问答机器人的优化&#xff0c;让我们看看更新了哪些新功能&#xff01; 那么&#xff0c;接下来就让我们来详细了解一下本次升级都带来了哪些新功能吧&#xff01; 知识库使用与管理…

【Linux】应用层协议:HTTP

URL 在之前的文章中我们实现了一个网络版本的计算器&#xff0c;在那个计算器中揉合了协议定制以及序列化反序列化的内容&#xff0c;我们当时也自己定制了一套协议标准&#xff0c;比如请求和响应的格式应该是什么&#xff1f;如何读到一个完整的报文&#xff1f;支持的运算符…

【路径规划】基于六次多项式的多关节机器人避障路径规划

最近迷上了机械臂避障轨迹规划&#xff0c;因为之前一直做的都是无障碍物轨迹规划&#xff0c;所以这次想试一下有障碍物的&#xff0c;把避障算法用在我的SimMechanics机械臂上&#xff0c;看看效果咋样。以下定义不区分路径规划和轨迹规划。   by the way&#xff0c;本文实…

探索CSS世界中的色彩艺术:从基础到实战

在网页设计与布局中&#xff0c;CSS&#xff08;Cascading Style Sheets&#xff09;赋予了我们无尽的创作可能。其中&#xff0c;色彩作为视觉传达的重要元素&#xff0c;直接影响着网站的整体风格与用户体验。本篇教程将带领您踏上CSS颜色的探索之旅&#xff0c;从基础概念到…

二叉树的定义和基本术语及性质

二叉树是一种特殊的树形数据结构&#xff0c;它对每个节点的子节点数进行了限制&#xff0c;即每个节点最多有两个子节点。这种结构使得二叉树成为了许多算法和数据结构的基础&#xff0c;如二叉搜索树、堆、哈夫曼编码等。本文将详细探讨二叉树的定义、基本术语和性质&#xf…

BGP扩展知识总结

一、BGP的宣告问题 在BGP协议中每台运行BGP的设备上&#xff0c;宣告本地直连路由在BGP协议中运行BGP协议的设备&#xff0c;来宣告通过IGP学习到的未运行BGP协议设备产生的路由&#xff1b;&#xff08;常见&#xff09; 在BGP协议中宣告本地路由表中路由条目时&#xff0c;将…

Unity构建详解(8)——SBP的Bundle生成

【WriteSerializedFiles】 这里将实际的写操作执行单独拎了出来共用&#xff0c;放在了IRunCachedCallbacks&#xff0c;但数据的传入和处理还是在Task中执行。 这一步会生成实际的SerializedFile文件&#xff0c;文件名就是之前的InternalName&#xff0c;但这还不是最终的B…

DNF手游攻略:2024新手攻略大全

在《DNF手游》的世界中&#xff0c;前期阶段对于新手玩家来说至关重要。以下是一份综合整理的新手攻略&#xff0c;帮助玩家快速适应游戏并取得进展。 1. 角色建立策略&#xff1a; 在前期&#xff0c;建议玩家建立3个角色&#xff0c;包括1个大号和2个小号。大号可以根据个人喜…

Vue3常见核心面试题(之二)

Q1&#xff1a;Vue3如何实现全局状态管理&#xff1f; A1: Vue3中使用provide&#xff08;&#xff09;和 inject()函数来实现全局状态管理 Q2&#xff1a;Vue3中的ref指令有哪些用途&#xff1f; A2&#xff1a;Vue3中的ref指令可以用来在组件内获取子组件的实例&#xff0c…

谷歌google浏览器无法更新Chrome至最新版本怎么办?浏览器Chrome无法更新至最新版本

打开谷歌google浏览器提示&#xff1a;无法更新Chrome&#xff0c;Chrome无法更新至最新版本&#xff0c;因此您未能获得最新的功能和安全修复程序。点击「重新安装Chrome」后无法访问此网站&#xff0c;造成谷歌浏览器每天提示却无法更新Chrome至最新版本。 谷歌google浏览器无…

SaaS知识库哪些比较好用?中小企业也能适用

在快节奏的商业世界中&#xff0c;拥有一个高效、易于使用的知识管理工具是提升工作效率的关键。对于中小企业来说&#xff0c;选择合适的SaaS&#xff08;软件即服务&#xff09;知识库平台尤为重要&#xff0c;因为它不仅能帮助员工快速找到信息&#xff0c;而且还能优化客户…

C语言运行时隐藏控制台

#include <windows.h> int main() {// 获取控制台窗口句柄HWND hwnd GetConsoleWindow();// 隐藏控制台窗口ShowWindow(hwnd, SW_HIDE);while (1){/* code */}return 0; }编译后运行&#xff0c;什么都没看到&#xff0c;打开任务管理器&#xff0c;在进程里能找到它。

数据结构进阶之堆

今天我们学习的是数据结构里面的堆&#xff0c;大家先看看我们今天要学习的内容 一、堆概念及认识 在学习堆之前我们得先明白完全二叉树是什么样子&#xff0c;因为堆是依据完全二叉树的结构来实现的&#xff0c;所以在这里我先告诉大家完全二叉树的是什么&#xff0c;如下图…

Excel中输入数字会改变怎么办?

一、数字显示不全&#xff0c;以“#”号代替 随着列宽的缩小&#xff0c;数字逐渐被“#”号代替&#xff08;首先数字的格式是“数值型&#xff0c;且只有整数”&#xff09; 原因分析&#xff1a;单元格中的数字无法完全显示&#xff0c;Excel会自动用“#”号填充剩余的空间 解…

00_如何使用国内镜像源下载QT

如何使用国内镜像源下载QT 如何使用国内镜像源下载QT 如何使用国内镜像源下载QT 第一步&#xff1a;下载下载qt online installer 网站&#xff1a;https://download.qt.io/official_releases/online_installers/ 添加链接描述 下载windows版本 第二步&#xff1a; 剪切放…