C++ AVL 树2025年3月17日 | 阅读 15 分钟 1962 年,GM Adelson-Velsky 和 EM Landis 创建了 AVL 树。为了纪念创建者,该树被称为 AVL。 AVL 树的定义是高度平衡的二叉搜索树,其中每个节点都有一个平衡因子,该平衡因子是通过从左子树的高度中减去右子树的高度来确定的。 如果每个节点的平衡因子介于 -1 和 1 之间,则认为树是平衡的;否则,需要平衡树。 平衡因子平衡因子 (k) = 高度 (左(k)) - 高度 (右(k))
为什么要使用 AVL 树?大多数 BST 操作,包括搜索、最大值、最小值、插入、删除等,都需要 O(h) 时间,其中 h 是 BST 的高度。对于倾斜的二叉树,这些操作的成本可能会增加到 O(n)。如果我们确保在每次插入和删除后树的高度保持 O(log(n)),我们可以为所有这些操作提供 O(log(n)) 的上限。AVL 树的高度始终为 O(log(n)),其中 n 是树的节点数。 AVL 树上的操作由于 AVL 树也是二叉搜索树,因此所有操作的执行方式与二叉搜索树中的操作相同。搜索和遍历不会导致 AVL 树属性的违反。然而,可能破坏此条件的动作是插入和删除;因此,需要对其进行审查。
AVL 树的插入为了确保在每次插入后提供的树保持 AVL,我们必须在典型的 BST 插入过程中添加一些重新平衡。 可以使用以下两个简单的操作(左键(左) 根键(右键))来平衡 BST,而不会违反 BST 属性。
插入的步骤如下
下面列出了在上述四种情况下要执行的过程。在每种情况下,我们只需要重新平衡以 z 为根的子树,并且一旦以 z 为根的子树的高度等于其插入前的值(通过适当的旋转),整个树就会平衡。 1. 左左情况 ![]() 2. 左右情况 ![]() 3. 右右情况 ![]() 4. 右左情况 ![]() 插入方法其思想是利用递归 BST 插入,在插入后,我们会单独收到指向每个祖先的自底向上的指针。因此,我们不需要父指针来向上移动。递归代码本身会向上移动并访问之前插入的每个节点。 为将该思想付诸实践,请遵循以下步骤
插入程序输出 Preorder traversal of the constructed AVL tree is 30 20 10 25 40 50 ………………………………………………………………………….. Process executed in 1.22 seconds Press any key to continue 说明 在旋转操作(左旋和右旋)期间仅更新少数几个点,因此所需时间是恒定的。更新高度和获取平衡因子也需要恒定的时间。因此,AVL 插入的时间复杂度与 BST 插入相同,即 O(h),其中 h 是树的高度。由于 AVL 树是平衡的(Logn),因此高度为 O。因此,AVL 插入的时间复杂度为 O(Logn)。 与红黑树比较红黑树 红黑树是一种自平衡二叉搜索树,每个节点拥有的额外位通常被理解为颜色(红色或黑色)。这些颜色的使用在插入和删除过程中保持了树的平衡。尽管树的平衡不是完美的,但足以缩短搜索时间并将其保持在 O(log n) 或以下,其中 n 是树组件的总数。Rudolf Bayer 于 1972 年发明了这种树。 通过使用 AVL 树和其他自平衡搜索树(如红黑树),所有基本操作都可以在 O(log n) 时间内完成。与红黑树相比,AVL 树的分布更均匀,尽管在插入和删除过程中可能会导致更多的旋转。因此,如果您的应用程序包含频繁的插入和删除,则推荐使用红黑树。此外,如果搜索的频率更高,而插入和删除的频率较低,则应选择 AVL 树而不是红黑树。 AVL 树的删除为了确保在每次删除后提供的树保持 AVL,我们必须在典型的 BST 删除过程中添加一些重新平衡。以下两个简单操作(左键(左) 根键(右键))可用于重新平衡 BST,而不会违反 BST 属性。
树的 T1、T2 和 T3 子树以 y(在左侧)或 x(在右侧)为根。 ![]() 上述两棵树中键的顺序如下 键(T1) < 键(x) < 键(T2) < 键(y) < 键(T3) 设 w 表示被删除的节点
就像插入一样,下面列出了在上述 4 种情况下要执行的过程。请注意,与插入不同,修复节点 z 可能不会完全修复 AVL 树。 1. 左左情况 ![]() 2. 左右情况 ![]() 3. 右右情况 ![]() 4. 右左情况 ![]() 与插入不同,在 z 处的旋转之后,可能需要在其祖先处进行旋转。因此,为了到达根节点,我们必须继续沿着路径前进。 删除方法下面提供了 AVL 树删除的 C 实现。递归 BST 删除是以下 C 实现的基础。在递归 BST 删除之后,我们依次收到指向每个祖先的自底向上指针。因此,向上移动不需要父指针。递归代码本身会向上移动并访问被删除节点的所有祖先。
输出 Preorder traversal of the constructed AVL tree is 9 1 0 -1 5 2 6 10 11 Preorder traversal after deletion of 10 1 0 -1 9 5 2 6 11 ……………………………………………………………………………. Process executed in 1.11 seconds Press any key to continue 说明 由于在旋转操作(左旋和右旋)期间仅更新少数几个点,因此所需时间是恒定的。获取平衡因子和更新高度都需要时间。因此,AVL 删除的时间复杂度为 O(h),其中 h 是树的高度,与 BST 删除相同。由于 AVL 树的平衡(Logn),高度为 O。因此,AVL 删除的时间复杂度为 O。(Log n)。 AVL 树的优点
总结
下一个主题C++ 中的 Des |
C++ 是一种强大的编程语言,提供了广泛的工具和功能来帮助程序员创建高效的代码。C++ 标准库中用于快速创建对的函数模板是 std::make_pair(),这是其中一个工具。在本文中,我们将...
阅读 4 分钟
在本文中,我们将讨论以及它们的特性和示例。在 C++ 语言中,关联数组将引用将键和值关联起来的数据结构。它们对于根据相应的键存储和检索值非常有效。这些关联数组是通过各种……实现的
阅读 4 分钟
简介:作为概率数据结构的布隆过滤器,提供了一种节省空间的方法来确定一个元素是否属于一个集合。自 1970 年由 Burton Howard Bloom 开发以来,它们已被广泛应用于许多计算机科学和工程领域。布隆过滤器非常有用...
阅读 6 分钟
? C++ 因其能够结合效率和通用性而受到竞争性编程的青睐。运行时通过其低级功能进行优化,这些功能对算法进行细粒度控制。代码开发通过标准模板库 (STL) 进行简化,该库提供了现成的数据结构和算法。面向对象、过程式和...
阅读 4 分钟
这个 C++ 食品店管理系统项目包含客户和产品搜索、显示、修改和删除等功能。此程序在允许用户提交订单前,会搜索文件中存储的客户信息。该软件专为小型...
阅读 19 分钟
? 在本文中,我们将讨论如何在 C++ 中创建用户定义数据类型的堆栈。但在讨论创建堆栈之前,我们必须了解堆栈。std::stack 是什么意思?堆栈是一种数据结构,使用后进先出 (LIFO) 原则...
阅读 4 分钟
在 C++ 中,名为 unordered_multimap 的关联容器包含由键和映射值组成的元素。虽然它支持具有相同键的许多组件,但它与 unordered_map 相似。使用 unordered_multimap 的主要好处是它允许公司...
阅读 4 分钟
在 C++ 中,静态变量是一种变量,其生命周期延伸到程序的整个执行过程,但其作用域可以根据其定义位置进行限制。我们最近介绍了 static 关键字如何改变变量的行为,这确保了它的...
7 分钟阅读
我们可以使用循环和算术运算符在 C++ 中反转数字。在此程序中,我们从用户那里获取数字作为输入并反转该数字。让我们看一个反转给定数字的简单 C++ 示例。示例 #include <iostream> using namespace std; int main() { int n, reverse=0, rem;...
阅读1分钟
在本文中,我们将讨论其方法和实现。一种流行的用于对各种竞技游戏中的玩家进行排名的评分方法是 Elo 评分方法。ELO 评分高于另一位玩家的玩家更有可能获胜...
阅读 4 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India