Python数据结构——AVL树的实现_光环大数据Python培训
数据结构之AVL树
左边为调整前得节点,我们可以看出k1的左右子树已不再满足AVL平衡 条件,调整后的为右图。 我们可以看出,解决办法是将z上移一层,并将x下移一层,由于在原树 中k2 > k1,所以k1成为k2的左子树,而y是大于k1的,所以成为k1的右 子树。 为了设计算法,我们这里来看一个更易理解的:插入的是节点“6”
1.3
插入操作
插入的核心思路是通过递归找到合适的位置,插入新结点,然后看新结
点是否平衡(平衡因子是否为2),如果不平衡的话,就分成三种大情 况以及两种小情况: 1. 在结点的左儿子(X < T->item) 在左儿子的左子树 (X < T->l-> item),“外边”,要 做单旋转。 在左儿子的右子树 (X > T->l-> item),“内部”,要 做双旋转。 2. 在结点的右儿子(X > T->item) 在右儿子的左子树(X < T->r-> item),“内部”,要 做双旋转。 在右儿子的右子树(X > T->r-> item),“外边”,要 做单旋转。 3. (X == T->item) ,对该节点的计数进行更新。 当进行了旋转之后,必定会有结点的“父结点”是需要更新的,例如: 2 / \ 1 4 / \ 3 5 \ 6 上图是调整前的,下图是调整后的: 4 / \ 2 5 / \ \ 1 3 6 可以看出,根结点2不平衡,是由于它的右儿子的右子树插入了新的结 点6造成的。因此,这属于“外边”的情况,要进行一次单旋转。于是 我们就把结点4调整上来作为根结点,再把结点2作为4的左儿子,最后 把结点2的右儿子修改为原来的结点4的左儿子。 实现代码: AVLTree Insert(Item X, AVLTree T ) { if( T == NULL ) { /* Create and return a one-node tree */
AVL树研究与实现
AVL树研究与实现摘要:计算机最广为人知的优点之一是其能储存大量的数据,如今随着时代的发展,储存容量更是犹如日进千里一般极速扩展,大容量的硬盘、u盘早已随处可见。
然而,要在巨大的数据中搜索出需要的内容却不是一件容易的事,由此,为了能减少在搜索储存数据上的开销,各种适应于不同访问搜索背景的数据结构应运而生。
树,便是计算机学科中最基本的数据结构之一,提供了快速的储存和访问性能。
该文探究了带有平衡条件的二叉查找树——avl树的原理,并对其使用c语言进行了实现。
关键词:数据结构;平衡二叉查找树;avl树中图分类号:tp311 文献标识码:a 文章编号:1009-3044(2013)07-1532-04对于大量的输入数据,普通的线性数据结构访问时间太慢,例如,对于一个有n个数据的线性数据结构,假设对每个数据的访问几率大致相同,每个数据每次访问有1/n的机会被访问,由于是线性数据,因此每个数据的访问花销可以经过一定的排列,最通常的是访问第一个数据花销1个单位时间,第二个2个单位时间,第三个3各单位时间……第n个n各单位时间,于是访问一次的平均花销为(n+[n2])/2n = (1+n)/ 2,用计算机专业的符号来说,其访问运行时间可以用o(n)来表示,即访问一次线性数据结构的花销在n这个数量级上。
使用树这一数据结构可将访问花销将至logn这个数量级上,也即o(logn),这里logn是以二为底的n的对数。
可以对比一下,若n=1267650600228229401496703205376,则logn=100。
数字越大,则o(n)与o(logn)相差越大。
一般来说,计算机学科中使用的最基本的树为二叉查找树,下图是一颗二叉树的简单示意图:图1 二叉树示意图二叉查找树则是在二叉树的基础上得来。
假设在一颗二叉树中,每个节点都有一个关键词值,并且关键词值都是互异且可以比较,若对于此二叉树中的每个节点,其左子树中所有节点的关键词值小于其本身关键词值,其右子树中所有关键词值大于其本身关键词值,则此二叉树为二叉查找树。
《python培训课件》数据结构
了解数据结构的概念,包括数据类型、线性结构、链表、栈、队列、树结构、 二叉树、堆、图结构等基础内容。
数据类型
学习Python中的各种数据类型,包括数字、字符串、列表、元组、字典、集 合等,以及它们在数据结构中的应用和特点。Fra bibliotek线性结构
1 线性表
学习线性表的定义、特点和操作,包括顺序表和链表。
2 栈与队列
了解栈和队列的概念、实现和应用,以及它们在算法中的重要性。
树结构
1
二叉树
掌握二叉树的定义、创建、遍历和常见操作,并了解二叉搜索树的特点和应用。
2
堆
学习堆的定义、实现和应用,包括最大堆和最小堆。
3
图结构
了解图的基本概念、表示方法和图算法,包括深度优先搜索和广度优先搜索。
排序算法
冒泡排序
其他常用算法
1 计数排序
通过确定每个元素的位置和数量,实 现线性时间复杂度的排序算法。
2 桶排序
将数据分到有限数量的桶中,再对每 个桶进行排序,最后合并桶中的数据。
3 基数排序
按照低位到高位的顺序,对数字进行排序,每一位都使用稳定的排序算法。
动态规划与贪心算法
动态规划
通过将问题划分为子问题,并保存子问题的解,来求 解复杂的问题。
贪心算法
每一步都选择当前最优解,从而逐步得到全局最优解, 不一定是最优解,但常常可以作为近似解。
数据结构实践与应用案例分析
应用所学的数据结构和算法解决实际问题,如建立图形界面、编写算法和进行大规模数据处理等。
通过比较相邻元素的大 小,依次交换元素位置, 将最大或最小的元素冒 泡到最后。
选择排序
从未排序的元素中找到 最小值,放到已排序的 末尾,然后继续从未排 序的元素中选择最小值。
数据结构与算法(5):AVL树
平衡⼆二叉树(AVL树,发明者的姓名缩写):⼀一种⾼高度平衡的排序⼆二叉树,其每⼀一个节点的左⼦子树和右⼦子树的⾼高度差最多等于1。
平衡⼆二叉树⾸首先必须是⼀一棵⼆二叉排序树!平衡因⼦子(Balance Factor):将⼆二叉树上节点的左⼦子树深度减去右⼦子树深度的值。
对于平衡⼆二叉树所有包括分⽀支节点和叶节点的平衡因⼦子只可能是-1,0和1,只要有⼀一个节点的因⼦子不不在这三个值之内,该⼆二叉树就是不不平衡的。
最⼩小不不平衡⼦子树:距离插⼊入结点最近的,且平衡因⼦子的绝对值⼤大于1的节点为根的⼦子树。
n个结点的AVL树最⼤大深度约1.44log2n。
查找、插⼊入和删除在平均和最坏情况下都是O(logn)。
增加和删除可能需要通过⼀一次或多次树旋转来重新平衡这个树。
这个⽅方案很好的解决了了⼆二叉查找树退化成链表的问题,把插⼊入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。
但是频繁旋转会使插⼊入和删除牺牲掉O(logN)左右的时间,不不过相对⼆二叉查找树来说,时间上稳定了了很多。
可以采⽤用动态平衡技术保持⼀一个平衡⼆二叉树。
构造平衡⼆二叉树的时候,也可以采⽤用相同的⽅方法,默认初始时,是⼀一个空树,插⼊入节点时,通过动态平衡技术对⼆二叉树进⾏行行调整。
Adeleon-Velskii和Landis提出了了⼀一个动态地保持⼆二叉排序树平衡的⽅方法,其基本思想是:在构造⼆二叉排序树的过程中,每当插⼊入⼀一个结点时,⾸首先检查是否因插⼊入⽽而破坏了了树的平衡性,若是因插⼊入结点⽽而破坏了了树的平衡性,则找出其中最⼩小不不平衡树,在保持排序树特性的前提下,调整最⼩小不不平衡⼦子树各结点之间的连接关系,以达到新的平衡。
通常这样得到的平衡⼆二叉排序树简称为AVL树。
⾼高度差2。
容易易看出,这种不不平衡出现在下⾯面四种情况:为使树恢复平衡,我们把k2变成这棵树的根节点,因为k2⼤大于k1,把k2置于k1的右⼦子树上,⽽而原本在k1右⼦子树的Y⼤大于k1,⼩小于k2,就把Y置于k2的左⼦子树上,这样既满⾜足了了⼆二叉查找树的性质,⼜又满⾜足了了平衡⼆二叉树的性质。
AVL树——精选推荐
AVL树1,AVL树⼜称平衡⼆叉树,它⾸先是⼀颗⼆叉查找树,但在⼆叉查找树中,某个结点的左右⼦树⾼度之差的绝对值可能会超过1,称之为不平衡。
⽽在平衡⼆叉树中,任何结点的左右⼦树⾼度之差的绝对值会⼩于等于 1。
2,为什么需要AVL树呢?在⼆叉查找树中最坏情况下查找某个元素的时间复杂度为O(n),⽽AVL树能保证查找操作的时间复杂度总为O(logn)。
3.avl树通过单旋转或者双旋转来实现保证树的平衡avl树和伸展树有很多相似之处,可以查看:伸展树的特点;AVL树AVL树是根据它的发明者G. M. Adelson-Velskii和E. M. Landis命名的。
它是⼀种特殊的。
AVL树要求: 任⼀节点的左⼦树深度和右⼦树深度相差不超过1(空树的深度为0。
注意,有的教材中,采⽤了不同的深度定义⽅法,所以空树的深度为-1)下⾯是AVL树:AVL树AVL树的特性让⼆叉搜索树的节点实现平衡(balance):节点相对均匀分布,⽽不是偏向某⼀侧。
因此,AVL树的搜索算法复杂度是log(n)的量级。
我们在中定义的操作,除了插⼊,都可以⽤在AVL树上 (假设使⽤懒惰删除)。
如果进⾏插⼊操作,有可能会破坏AVL树的性质,⽐如:插⼊2: 破坏AVL树观察节点5,它的左⼦树深度为2,右⼦树深度为0,所以左右两个⼦树深度相差为2,不再是AVL树。
由于2的加⼊,从节点6,1,5,3到2的层数都增加1。
6, 1, 5节点的AVL性质都被破坏。
如果从节点2向上回溯,节点5是第⼀个被破坏的。
从节点3开始的⼦树深度加1,这是造成6, 1, 5的AVL性质被破坏的本质原因。
我们将5和3之间的路径画成虚线(就好像挂了重物,边被拉断⼀样)。
我们可以通过单旋转(single rotation),调整以5为根节点的⼦树,来修正因为插⼊⼀个元素⽽引起的对AVL性质的破坏。
如下:Single rotation: 左侧超重,向右转通过单旋转,3成为新的根节点,2,5称为3的左右⼦节点。
平衡二叉树的实现及分析
平衡二叉树的实现及分析平衡二叉树(Balanced Binary Tree),也称为AVL树,是一种自平衡二叉查找树。
它的每个节点都包含一个额外的平衡因子,即左子树的高度减去右子树的高度,取值为-1、0或1、通过维护这个平衡因子,AVL树可以在查找、插入和删除操作中自动保持平衡,从而保证了较高的性能。
AVL树的实现基于二叉查找树(Binary Search Tree),它的插入和删除操作与二叉查找树相同。
然而,当进行插入或删除操作后,AVL树需要通过旋转操作保持平衡,这是AVL树与普通二叉查找树的主要区别。
AVL树的平衡性保证了树的高度不超过O(log n),这使得查找、插入和删除的平均时间复杂度都为O(log n)。
具体而言,当插入或删除操作导致树不再平衡时,需要进行以下四种旋转操作之一来恢复平衡:1. 左旋(Left Rotation):以当前节点为支点,将其右子节点变为新的根节点,并将原根节点作为新根节点的左子节点。
2. 右旋(Right Rotation):以当前节点为支点,将其左子节点变为新的根节点,并将原根节点作为新根节点的右子节点。
3. 左右旋(Left-Right Rotation):先对当前节点的左子节点进行左旋操作,然后再对当前节点进行右旋操作。
4. 右左旋(Right-Left Rotation):先对当前节点的右子节点进行右旋操作,然后再对当前节点进行左旋操作。
具体的实现中,需要对每个节点保存其高度信息。
在进行插入和删除操作时,先按照二叉查找树的规则进行操作,并更新节点的高度信息。
然后,逐级向上检查每个节点的平衡因子,如果平衡因子不在[-1,0,1]的范围内,就进行相应的旋转操作。
完成旋转后,需要更新相关节点的高度信息。
AVL树的平衡性能保证了在最坏情况下的时间复杂度为O(log n),不过由于维护平衡需要进行旋转操作,相对于普通的二叉查找树,AVL树的插入和删除操作可能会较慢一些。
数据结构课程设计AVL树实现及其分析实验报告
算法与数据结构课程设计报告题目: A VLree的实现及分析班级: 12计算机1学号: ************: ***成绩:2013年12月31日一、AVLree的实现及分析AVL 树是平衡的二元查找树。
一株平衡的二元查找树就是指对其每一个节点,其左子树和右子树的高度只差不超过1.编写程序实现AVL树的判别;并实现AVL树的ADT,包括其上的基本操作;节点的加入和删除。
BSt和AVL的差别就在平衡性上,所以AVL的操作关键要考虑如何在保持二元查找树定义条件下对二元树进行平衡化。
(1)编写AVL树的判别程序,并判别一个人元查找数是否为AVL树。
二元查找树用其先序遍历结果表示,如:5,2,1,3,7,8.(2)实现AVL树的ADT,包括其上的基本操作:节点的加入和删除,另外包括将一般二元查找树转变为AVL树的操作。
二、设计思想(宋体,三号加粗)任意给定一组数据,设计一个算法,建立一棵平衡二叉树,对它进行查找、插入、删除等操作。
平衡二叉树ADT结构如下:typedef struct{Status key;}ElemType;typedef struct BSTNode{ElemType data;Status bf;struct BSTNode *lchild,*rchild;}BSTNode,*BSTree;给出一组数据,通过InsertAVL(BSTree &T, ElemType e, Status &taller)插入算法,构建平衡二叉树,若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个数据元素为e的新结点,并返回1,否则返回0。
若因插入而使二叉排序树失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。
在此算法中,利用到递归算法和LeftBalance(BSTree &T)左平衡处理,RightBalance(BSTree &T)右平衡处理。
数据结构中的平衡二叉树AVL树和红黑树的原理与实现
数据结构中的平衡二叉树AVL树和红黑树的原理与实现在计算机科学中,数据结构是指一种组织和存储数据的方式,同时也是一种操作数据的方法。
其中,平衡二叉树是一种常用的数据结构,在平衡二叉树中,每个节点的左子树和右子树的高度最多相差1。
然而,平衡二叉树在插入和删除节点时可能会出现树结构不平衡的问题,这就引出了AVL树和红黑树的概念。
一、AVL树的原理与实现AVL树是由G. M. Adelson-Velsky和E. M. Landis于1962年提出的一种自平衡二叉查找树。
它通过在每个节点中添加一个平衡因子来维持树的平衡性。
平衡因子可以是-1、0或1,对应于左子树比右子树高、左右子树高度相等以及右子树比左子树高的情况。
在插入或删除节点时,AVL树会通过旋转操作来调整树的结构,以保持平衡因子的平衡。
旋转操作有四种情况:左旋、右旋、先左旋后右旋和先右旋后左旋。
通过这些旋转操作,AVL树能够保持树的平衡性,从而提高查找、插入和删除操作的效率。
AVL树的实现需要考虑节点的旋转、平衡因子的更新以及树的遍历等问题。
在节点的插入和删除操作中,需要对节点进行平衡处理,并更新相应的平衡因子。
在树的遍历中,可以使用中序遍历、前序遍历或后序遍历等方式来访问树的节点。
二、红黑树的原理与实现红黑树是由Rudolf Bayer在1972年提出的一种平衡二叉查找树。
它通过在每个节点中添加一个额外的属性表示节点的颜色(红色或黑色)来保持树的平衡性。
红黑树具有以下性质:1. 每个节点要么是红色,要么是黑色。
2. 根节点是黑色。
3. 每个叶子节点(NIL节点)是黑色。
4. 如果一个节点是红色,则它的两个子节点都是黑色。
5. 对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点。
通过这些性质,红黑树可以保持树的黑色平衡,在插入和删除节点时通过颜色变换和旋转操作来维持树的平衡性。
与AVL树相比,红黑树的调整操作较为简单,适用于动态插入和删除节点的情况。
《python培训》数据结构PPT课件
掌握数据结构,是进行高级编程和算法分析的基础。了解数据结构能够帮助 你更高效地解决问题,并编写出更优秀的代码。
什么是数据结构?
抽象数据结构
数据对象以及在该对象上定义的操作。
内部数据表示
数据和下标之间的关系的物理表示。
数据操作
对数据对象定义的操作的实现。
数据类型
查找节点
顺序查找,时间复杂度为O(n)。
常见数据结构:栈与队列
栈
一种操作受限的线性结构,特点是后进先出。
队列
一种操作受限的线性结构,特点是先进先出。
栈操作(进出栈)
进栈
接受一个元素,放到栈顶。
出栈
把栈顶元素移除,并返回它。
队列操作(进出队列)
进队列
把元素加入队列尾部。
出队列
从队列头部删除元素,并返回该元素。
一种数据对象及其相关操作。
数据结构分类
线性结构
数组 链表 栈 队列
非线性结构
树 图
算法与数据结构
1
算法
一组执行特定任务的有序操作。
2
数据结构
组织数据的不法时间复杂度来衡量算法的效率。
常见数据结构:数组
1 定义
一种线性结构,内存上连续存储。
3 优点
随机存储,寻址速度快。
常见数据结构:树
二叉树
每个节点最多有两个子节点。
二叉搜索树
二叉树的一种,按照左小右大 的规则建树。
平衡二叉树
一种特殊的二叉搜索树,任意 节点的左右子树高度差不超过1。
树的遍历
DFS
深度优先搜索,分为前序遍历、中序遍历、后序遍 历。
BFS
广度优先搜索,按层次访问。
java数据结构与算法之平衡二叉树(AVL树)的设计与实现分析
java数据结构与算法之平衡二叉树(A VL树)的设计与实现普通二叉查找树的问题在开篇,我们提到过,普通二叉树(二叉查找树)在操作的时间复杂度上不一定遵循O(㏒n),也有可能是O(n),这是为什么呢?在上一篇中,我们明明插入都按照一定规则比较的呀,其实那是因为我们在上篇测试时执行了随机插入的操作,如果此时利用上篇实现的二叉搜索树将一段已排序好的数据一个个插入后,就会发现如下情况了:从图中我们可以发现,把已排序的1-9数据进行正序和倒序插入后,树的结构已变成单向左子树或者右子树了,如果我们在往里插入已排序的数据,那么单向左子树或者右子树越来越长,此时已跟单链表没有什么区别了,因此对此结构的操作时间复杂度自然就由O(㏒n)变成O(n)了,这也就是普通二叉查找树不是严格意义上O(㏒n)的原因。
那么该如何解决这个问题呢?事实上一种解决的办法就是要有一个称为平衡的附加结构条件即:任何结点的深度不得过深,而这种数据结构就是我们本篇要分析的平衡二叉树(AVL),它本身也是一种二叉查找树,只不过不会出现前面我们分析的情形罢了,接下来我们就来分析一下这棵平衡二叉树。
平衡二叉树的定义通过上面的分析,我们明白的普通二叉查找树的不足,也知道了如何去解决这个缺点,即构建树时要求任何结点的深度不得过深(子树高度相差不超过1),而最终这棵树就是平衡二叉树(BalancedBinaryTree),它是G.M.Adelson-Velsky和ndis在1962年在论文中发表的,因此又叫AVL树。
这里我们还需要明确一个概念,AVL树只是实现平衡二叉树的一种方法,它还有很多的其他实现方法如红黑树、替罪羊树、Treap、伸展树等,后面我们还会分析其他树的实现。
ok~,接着来了解一下AVL树的特性:一棵AVL树是其每个结点的左子树和右子树的高度最多相差1的二叉查找树(空树的高度为-1),这个差值也称为平衡因子(其取值可以是1,0,-1,平衡因子是某个结点左右子树层数的差值,有的书上定义是左边减去右边,有的书上定义是右边减去左边,这样可能会有正负的区别,但是这个并不影响我们对平衡二叉树的讨论)。
平衡二叉树的实现及分析
平衡二叉树的实现及分析平衡二叉树(Balanced Binary Tree),也称为AVL树,是一种二叉树的特殊类型。
它的特点是树的所有节点的左子树和右子树的高度差不超过1,即任意节点的子树高度差的绝对值不超过1、通过保持树的平衡性,可以有效地提高树的查询效率。
```pythonclass Node:def __init__(self, val):self.val = valself.left = Noneself.right = Noneself.height = 1```接下来是平衡二叉树的实现:```pythonclass AVLTree:def __init__(self):self.root = None#获取节点高度def get_height(self, node):if not node:return 0return node.height#获取节点的平衡因子def get_balance_factor(self, node):if not node:return 0return self.get_height(node.left) -self.get_height(node.right)#左旋转def left_rotate(self, node):new_root = node.rightnode.right = new_root.leftnew_root.left = nodenode.height = 1 + max(self.get_height(node.left),self.get_height(node.right))new_root.height = 1 + max(self.get_height(new_root.left), self.get_height(new_root.right))return new_root#右旋转def right_rotate(self, node):new_root = node.leftnode.left = new_root.rightnew_root.right = nodenode.height = 1 + max(self.get_height(node.left),self.get_height(node.right))new_root.height = 1 + max(self.get_height(new_root.left), self.get_height(new_root.right))return new_root#插入节点def insert_node(self, root, val):if not root:return Node(val)elif val < root.val:root.left = self.insert_node(root.left, val)else:root.right = self.insert_node(root.right, val)root.height = 1 + max(self.get_height(root.left),self.get_height(root.right))balance_factor = self.get_balance_factor(root) if balance_factor > 1:if val < root.left.val:return self.right_rotate(root)else:root.left = self.left_rotate(root.left)return self.right_rotate(root)if balance_factor < -1:if val > root.right.val:return self.left_rotate(root)else:root.right = self.right_rotate(root.right) return self.left_rotate(root)return root#中序遍历def inorder_traversal(self, root):if root:self.inorder_traversal(root.left)print(root.val)self.inorder_traversal(root.right)```在上述代码中,`get_height`函数用于获取节点的高度,`get_balance_factor`函数用于计算节点的平衡因子,`left_rotate`函数实现了左旋转操作,`right_rotate`函数实现了右旋转操作。
数据结构(Python版)教学大纲 及 教案
数据结构(Python版)教学大纲及教案教学目标:1. 理解Python编程语言中数据结构的基本概念。
2. 掌握常用的数据结构如列表、元组、字典、集合及其操作方法。
3. 学会运用Python实现基本的数据结构操作,并解决实际问题。
教学内容:一、Python编程环境简介1. Python语言的特点和优势2. Python的安装和运行3. Python的基本语法二、数据结构基础1. 数据结构的概念和分类2. 线性结构:列表、元组3. 非线性结构:字典、集合三、列表和元组1. 列表的定义和特点2. 列表的基本操作:索引、切片、添加、删除、排序等3. 元组的定义和特点4. 元组的基本操作:索引、切片、添加、删除等四、字典和集合1. 字典的定义和特点2. 字典的基本操作:键值对添加、删除、修改、查找等3. 集合的定义和特点4. 集合的基本操作:添加、删除、交集、并集、差集等五、数据结构在实际问题中的应用1. 数组和链表的实现2. 栈和队列的实现3. 树和图的实现4. 排序和搜索算法的实现教学方法:1. 讲授法:讲解数据结构的基本概念、分类和操作方法。
2. 示例法:通过实际代码示例演示数据结构的应用。
3. 练习法:让学生通过编写代码练习数据结构的基本操作。
4. 讨论法:分组讨论实际问题,引导学生运用数据结构解决实际问题。
教学评价:1. 课堂参与度:观察学生在课堂上的发言和提问情况,了解学生的学习状态。
2. 代码练习:检查学生编写的代码,评估学生对数据结构操作的掌握程度。
3. 课后作业:布置相关课后作业,巩固学生对数据结构的理解和应用能力。
4. 小组项目:评估学生在小组项目中的表现,考察学生运用数据结构解决实际问题的能力。
六、数组和链表的实现1. 数组的定义和特点2. 使用Python实现数组及其操作3. 链表的定义和特点4. 使用Python实现链表及其操作七、栈和队列的实现1. 栈的定义和特点2. 使用Python实现栈及其操作3. 队列的定义和特点4. 使用Python实现队列及其操作八、树和图的实现1. 树的基本概念和类型2. 使用Python实现二叉树及其操作3. 图的基本概念和类型4. 使用Python实现图及其操作九、排序和搜索算法的实现1. 排序算法的基本概念和类型2. 使用Python实现常见排序算法(如冒泡排序、选择排序、插入排序等)3. 搜索算法的基本概念和类型4. 使用Python实现常见搜索算法(如深度优先搜索、广度优先搜索、二分搜索等)十、项目实践1. 结合实际问题,设计一个简单的数据结构应用项目2. 分组进行项目开发,引导学生运用所学知识解决实际问题3. 评估学生在项目中的表现,考察学生对数据结构知识的掌握和应用能力教学资源:1. 教案、PPT课件和教学代码示例2. Python编程环境(如PyCharm、VSCode等)3. 编程教材和在线教程4. 网络资源和相关论文教学进度安排:1. 每周安排2-3课时进行理论讲解和代码演示2. 每节课后布置相关的编程练习,巩固所学知识3. 每个章节结束后进行小组讨论和项目实践重点和难点解析一、Python编程环境简介补充说明:介绍Python的简洁明了的语法特点,如动态类型、缩进语法等;详细讲解Python的安装和运行过程;举例说明Python的基本语法规则。
AVL树了解AVL树的平衡性和旋转操作
AVL树了解AVL树的平衡性和旋转操作AVL树,全称Adelson-Velsky-Landis树,是一种经典的自平衡二叉搜索树。
在AVL树中,任意节点的左子树和右子树的高度差不超过1,这保证了树的平衡性。
为了维持平衡,AVL树在插入和删除节点时,会通过旋转操作来调整树的结构。
下面我们将了解AVL树的平衡性以及旋转操作的原理和步骤。
一、AVL树的平衡性AVL树的平衡性是指树的任意节点的左子树和右子树的高度差不超过1。
为了实现这种平衡性,AVL树的节点需要存储每个子树的高度信息,并在插入和删除节点时,通过旋转操作来调整树的结构,以维持平衡。
二、旋转操作的原理和步骤旋转操作是AVL树用来调整结构的主要方法,分为左旋和右旋两种。
下面我们将详细介绍这两种旋转操作的原理和步骤。
1. 左旋左旋操作是指将当前节点的右子节点上移,当前节点成为新的左子节点。
左旋操作的原理如下:(1)将当前节点的右子节点的左子节点作为当前节点的右子节点;(2)将当前节点的右子节点作为新的根节点;(3)将当前节点作为右子节点的左子节点。
左旋操作的步骤如下:(1)判断当前节点是否有右子节点,若没有,则无法进行左旋操作;(2)保存当前节点的右子节点,并将右子节点的左子节点设置为当前节点的右子节点;(3)将当前节点的右子节点设为右子节点的左子节点;(4)将右子节点设为当前节点的左子节点;(5)更新当前节点和右子节点的高度信息。
2. 右旋右旋操作是指将当前节点的左子节点上移,当前节点成为新的右子节点。
右旋操作的原理如下:(1)将当前节点的左子节点的右子节点作为当前节点的左子节点;(2)将当前节点的左子节点作为新的根节点;(3)将当前节点作为左子节点的右子节点。
右旋操作的步骤如下:(1)判断当前节点是否有左子节点,若没有,则无法进行右旋操作;(2)保存当前节点的左子节点,并将左子节点的右子节点设置为当前节点的左子节点;(3)将当前节点的左子节点设为左子节点的右子节点;(4)将左子节点设为当前节点的右子节点;(5)更新当前节点和左子节点的高度信息。
AVL树插入(Python实现)
AVL树插⼊(Python实现)建⽴AVL树1class AVLNode(object):2def__init__(self,data):3 self.data = data4 self.lchild = None5 self.rchild = None6 self.parent = None7 self.bf = 089class AVLTree(object)10def__init__(self,li=None)11 self.root = None12if li:13for val in li:14 self.insert(self.root,val)1516def insert(self,node,val):17if not node:18 node = AVLNode(val)19elif val < node.data:20 node.lchild = self.insert(node.lchild,val)21 node.lchild.parent = node22elif val > node.data:23 node.rchild = self.insert(node.rchild,val)24 node.rchild.parent = node25return nodeView Code左旋转、右旋转1def rorate_left(self,p,c):2 s2 = c.lchild3 p.rchild = s24if s2:5 s2.parent = p6 c.lchild = p7 p.parent = c8 p.bf = 09 c.bf = 010return c1112def rorate_right(self,p,c):13 s2 = c.rchild14 p.lchild = s215if s2:16 s2.parent17 c.rchild = p18 p.parent = c19 p.bf = 020 c.bf = 021return cView Code右→左旋转、左→右旋转1def rotate_right_left(self,p,c):2 g = c.lchild34#右旋5 s3 = g.rchild #1.把右孩⼦拿出来6 c.lchild = s3 #2.右孩⼦交给 C7if s3:8 s3.parent = c9 g.rchild = c #3.链接右孩⼦10 c.parent = g #4.链接⽗结点1112#左旋13 s2 = g.lchild14 p.rchild = s215if s2:16 s2.parent = p17 g.lchild = p18 p.parent = g1920#更新bf21if g.bf > 0: #插⼊到s3 #是指刚插⼊节点的g的平衡值22 p.bf = -123 c.bf = 024elif g.bf < 0: #插⼊到s225 p.bf = 026 c.bf = 127else: #插⼊的是G本⾝28 p.bf = 029 c.bf = 030 g.bf = 031return g3233def rotate_left_right(self,p,c):34 g = c.rchild3536#左旋37 s2 = g.lchild38 c.rchild = s239if s2:40 s2.parent = c41 g.lchild = c42 c.parent = g4344#右旋45 s3 = g.rchild46 p.lchild = s347if s3:48 s3.parent = p49 g.rchild = p50 p.parent = g5152#更新bf53if g.bf < 0: #插⼊到s254 p.bf = 155 c.bf = 056elif g.bf > 0: #插⼊到s357 p.bf = 058 c.bf = -159else: #插⼊的是G本⾝60 p.bf = 061 c.bf = 062 g.bf = 063return gView Code插⼊1def insert_no_rec(self,val):2#1.插⼊3 p = self.root4if not p:5 self.root = AVLNode(val)6return7while True:8if val < p.data:9if p.lchild: #左孩⼦存在10 p = p.lchild11else: #左孩⼦不存在12 p.lchild = AVLNode(val)13 p.lchild.parent = p14 node = p.lchild #node 存储的就是插⼊的节点15break16else val > p.data:17if p.rchild:18 p = p.rchild19else:20 p.rchild = AVLNode(val)21 p.rchild.parent = p22 node = p.rchild23break24else: #等于 #同样的元素不多次插⼊25#avl尽量不允许两个相同的数插⼊26return2728#2.更新balance factor29while node.parent: #node.parent 不为空时30if node.parent.lchild == node: #传递节点是在左⼦树,左⼦树更沉了31#第⼀乱循环,更新node.parent的bf -= 132if node.parent.bf < 0: #原来node.parent.bf == -1 (更新后会变成-2) 33# 做旋转34# 看node哪边沉35 head = node.parent.parent #为了链接旋转之后的⼦树36 tmp = node.parent #旋转前的⼦树的根37if node.bf > 0:38 n = self.rotate_left_right(node.parent,node)39else:40 n = self.rorate_right(node.parent,node)41elif node.parent.bf > 0: #原来node.parent.bf == 1 (更新后变成0) 42 node.parent.bf = 0 #平衡,即可以不需要确认⽗亲节点43break44else: #原来node.parent.bf = 0,更新之后变成-145 node.parent.bf = -146 node = node.parent47continue48else: #传递节点是在右⼦树,右⼦树更沉了49if node.parent.bf > 0:50 head = node.parent.parent51 tmp = node.parent52if node.bf < 0:53 n = self.rotate_right_left(node.parent,node)54else:55 n = self.rorate_left(node.parent,node)56elif node.parent.bf < 0:57 node.parent.bf = 058break59else:60 node.parent.bf = 161 node = node.parent62continue6364#3.链接旋转后的⼦树(只有做了旋转之后才会到这⼀步)65 n.parent = head66if head: #head不是空67if tmp == head.lchild:68 head.lchild = n69else:70 head.rchild = n71break72else:73 self.root = n74breakView Code。
AVL树数据结构的特点与使用场景
AVL树数据结构的特点与使用场景AVL树是一种自平衡的二叉搜索树,它在插入或删除节点时会通过旋转操作来保持树的平衡,以确保树的高度始终保持在较小的范围内。
AVL树得名于其发明者Adelson-Velsky和Landis,是一种高度平衡的二叉搜索树,具有快速的查找、插入和删除操作的特点。
在本文中,将介绍AVL树数据结构的特点以及其在实际应用中的使用场景。
一、AVL树的特点1. 自平衡性:AVL树是一种自平衡的二叉搜索树,任何时刻,AVL 树的任意节点的左右子树的高度差不超过1。
当插入或删除节点后,AVL树会通过旋转操作来保持树的平衡,以确保树的高度始终保持在较小的范围内,从而保证了查找、插入和删除操作的时间复杂度为O(log n)。
2. 高度平衡:由于AVL树的自平衡性,使得树的高度相对较低,这样在进行查找操作时,平均查找时间较短,提高了搜索效率。
3. 严格平衡:AVL树是一种严格平衡的二叉搜索树,任何时刻,AVL树的任意节点的左右子树的高度差不超过1,这种严格平衡性保证了AVL树的高度始终保持在较小的范围内,使得其在各种操作下都能保持高效性。
4. 插入和删除操作复杂度低:由于AVL树的自平衡性,插入和删除节点时需要进行旋转操作来保持树的平衡,但这些旋转操作的时间复杂度为O(log n),因此插入和删除操作的复杂度仍然为O(log n),保证了操作的高效性。
二、AVL树的使用场景1. 数据库索引:在数据库系统中,AVL树常被用作索引结构,用于加速数据库的查找操作。
由于AVL树具有快速的查找、插入和删除操作,能够保持树的平衡,因此在数据库索引中得到广泛应用。
2. 编辑器中的自动补全功能:在文本编辑器或代码编辑器中,常常需要实现自动补全功能,AVL树可以用来存储单词或代码片段,通过快速查找实现自动补全功能,提高编辑效率。
3. 路由表:在网络路由中,需要快速查找目标地址对应的路由信息,AVL树可以用来存储路由表,通过快速查找实现高效的路由转发,提高网络传输效率。
大数据数据结构和算法_树2_AVL树部分
大数据数据结构和算法_树2_AVL树部分AVL树是一种自平衡二叉树,它的特点是每个节点的左子树和右子树的高度差不超过1、AVL树的平衡是通过旋转操作来实现的,这样可以保证树的高度始终在O(log n)的范围内。
AVL树的平衡是通过对节点进行四种旋转操作来实现的:LL、LR、RR、RL旋转。
LL旋转是指当一个节点的左子树的高度大于右子树的高度,并且左子树的左子树高度大于左子树的右子树高度时,需要进行LL旋转。
LL旋转是将当前节点的左子节点提升为根节点,然后将原根节点降为右子节点。
LR旋转是指当一个节点的左子树的高度大于右子树的高度,并且左子树的右子树高度大于左子树的左子树高度时,需要进行LR旋转。
LR旋转是先对当前节点的左子节点进行RR旋转,然后再对当前节点进行LL旋转。
RR旋转是指当一个节点的右子树的高度大于左子树的高度,并且右子树的右子树高度大于右子树的左子树高度时,需要进行RR旋转。
RR旋转是将当前节点的右子节点提升为根节点,然后将原根节点降为左子节点。
RL旋转是指当一个节点的右子树的高度大于左子树的高度,并且右子树的左子树高度大于右子树的右子树高度时,需要进行RL旋转。
RL旋转是先对当前节点的右子节点进行LL旋转,然后再对当前节点进行RR旋转。
AVL树的插入操作和二叉树的插入操作类似,都是先找到插入位置,然后将新节点插入到相应位置。
不同的是,在插入节点之后,需要向上回溯检查每个祖先节点的平衡因子。
如果一些祖先节点的平衡因子超过了1或者小于了-1,就需要进行相应的旋转操作,以恢复平衡。
AVL树的删除操作也和二叉树的删除操作类似,都是先找到要删除的节点,然后根据节点的情况进行删除。
删除节点之后,需要向上回溯检查每个祖先节点的平衡因子,进行相应的旋转操作以恢复平衡。
AVL树的优点是能够维护树的平衡性,使得在最坏情况下的、插入和删除操作的时间复杂度都是O(log n)。
然而,AVL树的缺点是在插入和删除操作中需要进行旋转操作,这会增加一定的时间开销。
avl tree的python代码
AVL树的Python代码一级标题:AVL树介绍二级标题:什么是AVL树AVL树是一种自平衡二叉搜索树,它的特点是任意节点的左子树和右子树的高度差不超过1。
AVL树是以其发明者Adelson-Velsky和Landis的名字命名的。
二级标题:AVL树的特点AVL树具有以下特点: 1. 每个节点都有一个平衡因子,它是左子树高度减去右子树高度。
2. 平衡因子可以为-1、0或1。
如果平衡因子为k,表示该节点的左子树高度比右子树高度大k。
3. 所有叶子节点的平衡因子都为0。
4. 插入或删除节点后,AVL树会自动调整以保持平衡性。
二级标题:为什么使用AVL树使用AVL树的好处有: 1. AVL树的高度始终保持在O(log n),使得搜索、插入和删除的平均时间复杂度为O(log n)。
2. AVL树自动调整以保持平衡性,不会像普通二叉搜索树一样退化成链表。
3. AVL树相比红黑树来说,旋转操作更少,具有更好的搜索性能。
一级标题:AVL树的实现二级标题:Node类的定义在实现AVL树之前,我们首先需要定义一个Node类,用于表示AVL树的节点。
Node类包含以下属性: - key:节点的键值 - left:指向左子节点的指针 - right:指向右子节点的指针 - height:节点的高度class Node:def __init__(self, key):self.key = keyself.left = Noneself.right = Noneself.height = 1二级标题:AVL树的插入操作AVL树的插入操作是通过递归实现的,基本思想是先执行二叉搜索树的插入操作,然后在返回的过程中进行平衡操作。
具体的插入操作分为以下几步: 1. 如果树为空,直接创建一个新节点并返回。
2. 如果插入的值小于当前节点的键值,则插入到左子树中。
3. 如果插入的值大于当前节点的键值,则插入到右子树中。
4. 更新当前节点的高度。
数据结构:AVL树
数据结构:AVL树⼆叉查找树的⼀个局限性就是有可能退化成⼀个链表,这种情况下⼆叉查找树的效率就会急剧下降变成0(n)。
⽽AVL树可以很好地解决BST的这种困境。
本篇博客会介绍AVL树的基本特点和相关操作。
⽂章参考⾃博客:1. 什么是AVL树任何两个⼦树的⾼度差最⼤是1,这样的⼆叉树叫做AVL树。
先来确定⼏个概念:平衡因⼦:将⼆叉树上节点的左⼦树⾼度减去右⼦树⾼度的值称为该节点的平衡因⼦BF(Balance Factor)。
最⼩不平衡⼦树:距离插⼊节点最近的,且平衡因⼦的绝对值⼤于1的节点为根的⼦树。
左边⼆叉树的节点45的BF = 1,插⼊节点43后,节点45的BF=2。
节点45是距离插⼊点43最近的BF不在[-1,1]范围内的节点,因此以节点45为根的⼦树为最⼩不平衡⼦树。
2. 节点的实现public class AVLTreeNode<T extends Comparable> {// 存储的数据-⽤于排序T key;// 节点⾼度-⽤于计算⽗节点的BFint height;// 左⼉⼦ & 右⼉⼦AVLTreeNode<T> left;AVLTreeNode<T> right;public AVLTreeNode() {}public AVLTreeNode(T key, AVLTreeNode<T> left, AVLTreeNode<T> right) {this.key = key;this.left = left;this.right = right;this.height = 0;}}节点的定义还是⽐较简单的,相对于之前的定义多了⼀个height属性⽤于计算⽗节点的BF。
树的定义public class AVLTree<T extends Comparable> {// 定义树的根节点AVLTreeNode<T> root;public AVLTree() {root = null;}}获取树的⾼度public int height() {return height(root);}private int height(AVLTreeNode<T> tree) {if (tree != null){return tree.height;}return 0;}本⽂章将空树的⾼度定义为0,⾼度以树的层次为准,根节点的⾼度为1,依次类推。
大数据数据结构和算法_树2_AVL树部分
Binary Decision Tree 二叉判定树
条件判定、分类、人工智能判定、游戏中 的情景判定
N-ary Tree 多叉树
B、B+、B*Tree 文件系统、数据 库索引(一维)
Q-Tree、OcTree 四叉、八叉树 空间索引、游戏 碰撞检测
R-Tree 矩型树 空间数据库索 引(多维)
4
3 4
对3进行 左单旋
5
要点: 右孩子右旋,自己左旋
4
3
5
树
AVL树的旋转要点: -LL型:右边缺,向右单旋,孩子-自己-孩子,右-左-右 -RR型:左边缺,向左单旋,孩子-自己-孩子,左-右-左 -LR型:右边缺,左右双旋,右孩子左旋,自己右旋 -RL型:左边缺,右左双旋,左孩子右旋,自己左旋 在编程时注意: 画出草图,区分类型,按照口诀,写出代码。 久了,对平衡的理解深刻了,自然就熟练了。 旋转平衡,说白了就是缺哪补哪,多余的按照保序要求给转移就 是。
4
对3进行 左单旋
5 4
3
对5进行 右单旋
要点: 左孩子左旋,自己右旋
4
3
5
树
将{3,5,4}转为AVL树
节点3的平衡因子-2,失去
平衡
3
3 5
3 5
对节点x进行右-左双旋(RL型): (1)对节点x的右子树y进行右单 旋; (2)对节点x进行左单旋
4
R L类型 ,右-左双 旋
3 对5进行 右单旋 5
LSM-Tree 日志型合并树 内存有序、外
存B+ LevelDB、
HBase
Trie-Tree 字典树
去重、前缀匹配、搜 索词提示、热词统计
数据结构平衡二叉树的操作演示
数据结构平衡二叉树的操作演示平衡二叉树(AVL树)是一种自平衡的二叉树,可以在O(log n)的时间内完成插入、删除和操作。
AVL树的平衡性是通过对树节点进行左旋和右旋操作来实现的。
下面将详细介绍AVL树的操作演示。
AVL树的定义和二叉树相似,每个节点包含一个键值和指向左右子树的指针。
任意节点的左子树和右子树的高度最多相差1,这个特性使得AVL树始终保持平衡。
1.插入操作插入操作是AVL树中最复杂的操作之一,因为插入后可能会破坏树的平衡性。
下面通过一个示例来演示AVL树的插入操作。
假设我们要向一棵空树插入节点5,插入过程如下:1.创建一个新节点,值为52.将新节点插入根节点。
3.检查树的平衡性。
根据AVL树的定义,左子树和右子树的高度差最多为1、在这个例子中,树是平衡的。
4.更新每个节点的高度值。
如果我们插入节点6,插入过程如下:1.创建一个新节点,值为62.将新节点插入到节点5的右子树。
3.检查树的平衡性。
在这个例子中,树不再是平衡的,因为节点5的左子树和右子树的高度差为24.执行旋转操作来恢复树的平衡性。
在这个例子中,我们需要对节点5进行左旋操作。
5.更新每个节点的高度值。
2.删除操作删除操作是AVL树中另一个可能破坏树的平衡性的操作。
下面通过一个示例来演示AVL树的删除操作。
假设我们要删除节点5,删除过程如下:1.在树中找到要删除的节点,即节点52.如果要删除的节点是叶子节点或只有一个子节点,直接删除。
在这个例子中,节点5是一个叶子节点,可以直接删除。
3.如果要删除的节点有两个子节点,找到其后继节点(即右子树中的最小节点)或前驱节点(即左子树中的最大节点)来取代它。
在这个例子中,我们找到节点6来取代节点54.如果取代节点是叶子节点或只有一个子节点,直接用它取代要删除的节点。
在这个例子中,我们用节点6取代了节点55.检查树的平衡性。
在这个例子中,树是平衡的。
6.更新每个节点的高度值。
3.左旋操作左旋操作用于恢复树的平衡性。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Python数据结构——AVL树的实现_光环大数据Python培训我们已经证明,保持 AVL 树的平衡将会使性能得到很大的提升,那我们看看如何在程序中向树插入一个新的键值。
因为所有的新键是作为叶节点插入树的,而新叶子的平衡因子为零,所以我们对新插入的节点不作调整。
不过一旦有新叶子的插入我们必须更新其父节点的平衡因子。
新叶子会如何影响父节点的平衡因子取决于叶节点是左子节点还是右子节点。
如果新节点是右子节点,父节点的平衡因子减 1。
如果新节点是左子节点,父节点的平衡因子将加 1。
这种关系可以递归地应用于新节点的前两个节点,并有可能影响到之前的每一个甚至是根节点。
由于这是一个递归的过程,我们看看更新平衡因子的两个基本条件:递归调用已到达树的根。
父节点的平衡因子已调整为零。
一旦子树平衡因子为零,那么父节点的平衡因子不会发生改变。
我们将实现 AVL 树的子类BinarySearchTree。
首先,我们将重写_put方法,并写一个新的辅助方法updateBalance。
这些方法如Listing 1 所示。
除了第 7 行和第 13 行对 updateBalance的调用,你会注意到_put和简单的二叉搜索树的定义完全相同。
Listing 1updateBalance方法完成了大部分功能,实现了我们刚提到的递归过程。
这个再平衡方法首先检查当前节点是否完全不平衡,以至于需要重新平衡(第 16 行)。
如果当前节点需要再平衡,那么只需要对当前节点进行再平衡,而不需要进一步更新父节点。
如果当前节点不需要再平衡,那么父节点的平衡因子就需要调整。
如果父节点的平衡因子不为零,算法通过父节点递归调用updateBalance 方法继续递归到树的根。
当对一棵树进行再平衡是必要的,我们该怎么做呢?高效的再平衡是使 AVL 树能够很好地执行而不牺牲性能的关键。
为了让 AVL 树恢复平衡,我们会在树上执行一个或多个“旋转”(rotation)。
为了了解什么是旋转,让我们看一个很简单的例子。
思考一下图 3 的左边的树。
这棵树是不平衡的,平衡因子为 -2。
为了让这棵树平衡我们将根的子树节点 A 进行左旋转。
图 3:使用左旋转变换不平衡树执行左旋转我们需要做到以下几点:使右节点(B)成为子树的根。
移动旧的根节点(A)到新根的左节点。
如果新根(B)原来有左节点,那么让原来B的左节点成为新根左节点(A)的右节点。
注:由于新根(B)是 A 的右节点,在这种情况下,移动后的 A 的右节点一定是空的。
我们不用多想就可以给移动后的 A 直接添加右节点。
虽然这个过程概念上看起来简单,但实现时的细节有点棘手,因为要保持二叉搜索树的所有性质,必须以绝对正确的顺序把节点移来移去。
此外,我们需要确保更新了所有的父节点。
让我们看一个稍微复杂的树来说明右旋转。
图 4 的左侧展现了一棵“左重”的树,根的平衡因子为 2。
执行一个正确的右旋转,我们需要做到以下几点:使左节点(C)成为子树的根。
移动旧根(E)到新根的右节点。
如果新根(C)原来有右节点(D),那么让 D 成为新根右节点(E)的左节点。
注:由于新根(C)是 E 的左节点,移动后的 E 的左节点一定为空。
这时可以直接给移动后的 E 添加左节点。
图 4:使用右旋转变换不平衡树现在你已经明白了旋转的过程,了解了旋转的方法,让我们看看代码。
Listing 2 同时显示了右旋转和左旋转的代码。
在第 2 行,我们创建一个临时变量来跟踪新的子树的根。
正如我们之前所说的新的根是旧根的右节点。
现在,右节点已经存储在这个临时变量中。
我们将旧根的右节点替换为新根的左节点。
下一步是调整两个节点的父指针。
如果newRoot原来有左节点,左节点的新父节点变成旧根。
新根的父节点将成为旧根的父节点。
如果旧根是整个树的根,那么我们必须让整棵树的根指向这个新的根。
如果旧根是左节点,那么我们改变左节点的父节点到一个新的根;否则,我们改变右节点的父节点到一个新的根(第10-13 行)。
最后我们设置的旧根的父节点成为新的根。
这里有很多复杂的中间过程,所以建议你一边看函数的代码,一边看图 3。
rotateRight方法和rotateLeft是对称的,所以请自行研究rotateRight的代码。
Listing 2最后,第 16-17 行需要解释一下。
这两行我们更新了旧根和新根的平衡因子。
因为其他操作都是移动整个子树,被移动的子树内的节点的平衡因子不受旋转的影响。
但我们如何在没有重新计算新的子树的高度的情况下更新平衡因子?下面的推导将让你明白,这些代码都是正确的。
图 5:左旋转图5显示了一个左旋转。
B 和 D 是中心节点,A,C,E 是其子树。
让 hX 表示以X为根节点的子树的高度。
通过定义我们知道:newBal(B)=hA−hColdBal(B)=hA−hD但我们知道,D 的高度也可以通过 1 + max(hC,hE) 给定,也就是说,D 的高度为两子树高度中较大者加 1。
记住,hC 和 hE 没有改变。
所以,把上式代入第二个方程,可以得到:oldBal(B)=hA−(1+max(hC,hE))然后两方程作差。
下面是作差的步骤,newBal(B) 使用了一些代数方法简化方程。
beginsplitnewBal(B)−oldBal(B)=hA−hC−(hA−(1+max(hC,hE)))newBal(B)−oldBal(B)=hA−hC−hA+(1+max(hC,hE))newBal(B)−oldBal(B)=hA−hA+1+max(hC,hE)−hCnewBal(B)−oldBal(B)=1+max(hC,hE)−hC接下来我们移动 oldBal(B) 到方程的右端并利用 max(a,b)−c = max(a−c,b −c)。
newBal(B)=oldBal(B)+1+max(hC−hC,hE−hC)但 hE − hC 等同于−oldBal(D)。
所以我们说:max(−a,−b) = −min(a,b),可以通过以下步骤完成对 newBal(B) 的推导:newBal(B)=oldBal(B)+1+max(0,−oldBal(D))newBal(B)=oldBal(B)+1−min(0,oldBal(D))现在方程所有的项都是已知数。
如果我们记得 B 是rotRoot,D 是newRoot,可以看出这正好符合第 16 行的语句:更新节点 D,以及右旋转后的平衡因子的方程推导与此类似。
现在你可能认为步骤都完全了解了。
我们知道如何并且什么时候进行左右旋转,但看看图 6。
由于节点 A 的平衡因子是 -2,我们应该做一个左旋转。
但是,当我们在左旋转时会发生什么?图 6:一棵更难平衡的不平衡树图 7:显示的树左旋转后,仍然不平衡。
如果我们要做一个右旋转来试图再平衡,又回到了开始的状态。
要解决这个问题,我们必须使用以下规则:如果子树需要左旋转使之平衡,首先检查右节点的平衡因子。
如果右节点左重则右节点右旋转,然后原节点左旋转。
如果子树需要右旋转使之平衡,首先检查左节点的平衡因子。
如果左节点右重则左节点左旋转,然后原节点右旋转。
图 8 显示了这些规则如何解决了我们在图 6 和图 7 中遇到的问题。
首先,以 C 为中心右旋转,树变成一个较好的形状;然后,以 A 为中心左旋转,整个子树恢复平衡。
图 8:右旋转后左旋转实现这些规则的代码可以从我们“再平衡”(rebalance)的方法中找到,如Listing 3 所示。
上面的第一条规则从第二行if语句中实现。
第二条规则是由第 8 行elif语句实现。
Listing 3通过保持树的平衡,我们可以确保get方法运行的时间复杂度为 O(log2n)。
但问题是put方法的时间复杂度是多少?我们把put操作进行分解。
由于每一个新节点都是作为叶节点插入的,每一轮更新所有父节点的平衡因子最多只需要log2n 次操作,每层执行一次。
如果子树是不平衡的最多需要两个旋转把子树恢复平衡。
但是,每个旋转的操作的复杂度为 O(1) ,所以即使我们进行put操作最终的复杂度仍然是 O(log2n)。
为什么大家选择光环大数据!大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请大数据领域具有多年经验的讲师,提高教学的整体质量与教学水准。
讲师团及时掌握时代的技术,将时新的技能融入教学中,让学生所学知识顺应时代所需。
通过深入浅出、通俗易懂的教学方式,指导学生较快的掌握技能知识,帮助莘莘学子实现就业梦想。
光环大数据启动了推进人工智能人才发展的“AI智客计划”。
光环大数据专注国内大数据和人工智能培训,将在人工智能和大数据领域深度合作。
未来三年,光环大数据将联合国内百所大学,通过“AI智客计划”,共同推动人工智能产业人才生态建设,培养和认证5-10万名AI大数据领域的人才。
参加“AI智客计划”,享2000元助学金!【报名方式、详情咨询】光环大数据网站报名:手机报名链接:http:// /mobile/。