数据结构-自平衡二叉查找树(AVL)详解

介绍:

在计算机科学中,AVL树是最先发明的自平衡二叉查找树。

在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。

查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 “An algorithm for the organization of information” 中发表了它。

特点:

AVL树本质上还是一棵二叉搜索树,它的特点是:

1.本身首先是一棵二叉搜索树。

2.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。

也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

节点数:

高度为 h 的 AVL 树,节点数 N 最多2^h ? 1; 最少N(h)=N(h? 1) +N(h? 2) + 1。

最少节点数n 如以斐波那契数列可以用数学归纳法证明:

即:

N(0) = 0 (表示 AVL Tree 高度为0的节点总数)

N(1) = 1 (表示 AVL Tree 高度为1的节点总数)

N(2) = 2 (表示 AVL Tree 高度为2的节点总数)

N(h)=N(h? 1) +N(h? 2) + 1 (表示 AVL Tree 高度为h的节点总数)

节点的平衡因子是它的左子树的高度减去它的右子树的高度。带有平衡因子 1、0 或 -1 的节点被认为是平衡的。带有平衡因子 -2 或 2 的节点被认为是不平衡的,并需要重新平衡这个树。平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来。

操作:

假设由于在二叉排序树上插入结点而失去平衡的最小子树根结点的指针为a(即a是离插入点最近,且平衡因子绝对值超过1的祖先结点),

则失去平衡后进行进行的规律可归纳为下列四种情况:

单向右旋平衡处理LL:

由于在*a的左子树根结点的左子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需进行一次右旋转操作;

单向左旋平衡处理RR:

由于在*a的右子树根结点的右子树上插入结点,*a的平衡因子由-1变为-2,致使以*a为根的子树失去平衡,则需进行一次左旋转操作;

双向旋转(先左后右)平衡处理LR:

由于在*a的左子树根结点的右子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需进行两次旋转(先左旋后右旋)操作。

双向旋转(先右后左)平衡处理RL:

由于在*a的右子树根结点的左子树上插入结点,*a的平衡因子由-1变为-2,致使以*a为根的子树失去平衡,则需进行两次旋转(先右旋后左旋)操作。

图解二叉树的操作:

1.左旋

2.右旋:

avl的插入操作:(邪恶脸)

1.单方向:

以节点5为基准进行右旋:

总结:

对于这种一个方向的,只需要一次操作,这是孩子都在左边的情况,对于孩子都在右边的情况,(5,8,10),以5为基准,进行一次左旋

2.双方向:

不是一个方向,进行两次操作,先转化为1的情况,再次旋转 ,显示3为基准,左旋,5为基准右旋,先左后右边

总结:

对于这种不一个方向的情况,需要两次操作,先转化为1的情况,对称的情况是先右后左。

删除操作:

从AVL树中删除可以通过把要删除的节点向下旋转成一个叶子节点,接着直接剪除这个叶子节点来完成。因为在旋转成叶子节点期间最多有 log n个节点被旋转,而每次 AVL 旋转耗费恒定的时间,删除处理在整体上耗费 O(log n) 时间。

查找:

在AVL树中查找同在一般BST完全一样的进行,所以耗费 O(log n) 时间,因为AVL树总是保持平衡的。不需要特殊的准备,树的结构不会由于查询而改变。(这是与伸展树查找相对立的,它会因为查找而变更树结构。)

时间复杂度分析:

在树, 二叉树, 二叉搜索树中提到,一个有n个节点的二叉树,它的最小深度为log(n),最大深度为n。比如下面两个二叉树:

深度为n的二叉树

深度为log(n)的二叉树

分析:

二叉搜索树的深度越小,那么搜索所需要的运算时间越小。一个深度为log(n)的二叉搜索树,搜索算法的时间复杂度也是log(n)。然而,我们在二叉搜索树中已经实现的插入和删除操作并不能让保持log(n)的深度。如果我们按照8,7,6,5,4,3,2,1的顺序插入节点,那么就是一个深度为n的二叉树。那么,搜索算法的时间复杂度为n。

我的微信二维码如下,欢迎交流讨论

欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!

微信订阅号二维码如下:

参考

http://baike.baidu.com/view/671745.htm

http://www.cnblogs.com/vamei/archive/2013/03/21/2964092.html

时间: 2024-10-11 06:50:29

数据结构-自平衡二叉查找树(AVL)详解的相关文章

13、自平衡二叉查找树AVL

1 package ren.laughing.datastructure.baseImpl; 2 3 /** 4 * 自平衡二叉查找树AVL 继承二叉查找树 5 * 6 * @author Laughing_Lz 7 * @time 2016年4月20日 8 */ 9 public class AVLTree extends BSTree { 10 /** 11 * 统一平衡方法 旋转操作 12 * 13 * @param z 14 * z是失衡的结点 15 * @return 返回平衡后子树的

二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较

http://www.iteye.com/topic/614070 此少侠总结的特棒,直接收藏了. 我们这个专题介绍的动态查找树主要有: 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree).这四种树都具备下面几个优势: (1) 都是动态结构.在删除,插入操作的时候,都不需要彻底重建原始的索引树.最多就是执行一定量的旋转,变色操作来有限的改变树的形态.而这些操作所付出的代价都远远小于重建一棵树.这一优势在<查找结构专题(1):静态查找结构概论 >中讲到

【查找结构3】平衡二叉查找树 [AVL]

在上一个专题中,我们在谈论二叉查找树的效率的时候.不同结构的二叉查找树,查找效率有很大的不同(单支树结构的查找效率退化成了顺序查找).如何解决这个问题呢?关键在于如何最大限度的减小树的深度.正是基于这个想法,平衡二叉树出现了. 平衡二叉树的定义 (AVL—— 发明者为Adel'son-Vel'skii 和 Landis) 平衡二叉查找树,又称 AVL树. 它除了具备二叉查找树的基本特征之外,还具有一个非常重要的特点:它 的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值(平衡因子

[重温数据结构]一种自平衡二叉查找树avl树的实现方法

最近重温<数据结构>,发现其中的东西我上学的时候几乎都没写过... 惭愧啊.于是打算一一写点.算是对我逝去青春的纪念... avl树的代码网上有很多, 这个在平衡二叉树里面算是比较简单的. 需要注意的就是树的平衡因子和其子树的平衡因子符号相反的旋转情况.这个在函数avl_rotate_right等中有处理. 目前只做了插入,删除等哪天想做了再做吧. avl.h 1 #define INSERT_ERROR -1 2 #define INSERT_OK 1 3 4 #define LEFT_LE

平衡二叉查找树——AVL树

二叉查找树在最坏情况下高度可能为N-1,即插入元素时后插入的元素总比以前插入的元素大或者小.为了解决这种不平衡的情况,引入了平衡条件来限制树中节点的深度不能过深,其中最老的一种平衡树称为AVL树.这种树限制树中每个节点的左右子树的高度相差不能超过一.(另一种更严格的树限制节点的左右子树高度必须相等,但这样的树要求树中的节点数目为2的k次幂减1,是一种理想平衡树,但是要求太严格,无法实际使用.) AVL树平衡条件分析 AVL树是一棵特殊的二叉查找树,对AVL树的操作中,除了插入操作与普通二叉查找树

平衡二叉查找树AVL

1.AVL简介 这篇文章我们要介绍的是能够在key插入时一直保持平衡的二叉查找树(AVL树,AVL是发明者的名字缩写) 利用AVL实现ADT MAP,基本上与BST的实现相同.不同之处在于二叉树的生成与维护过程. 2.AVL中的概念 AVL树的实现中,需要对每个节点跟踪"平衡因子balance factor"参数. 平衡因子是根据节点的左右子树的高度来定义的.确切的来说,是左右子树的高度差.balanceFactor = height(leftSubTree) - height(rig

数据结构与算法—线性表详解

前言 通过前面数据结构与算法前导我么知道了数据结构的一些概念和重要性,那么我们今天总结下线性表相关的内容.当然,我用自己的理解解分享给大家. 其实说实话,可能很多人依然分不清线性表,顺序表,和链表之间的区别和联系! 线性表:逻辑结构, 就是对外暴露数据之间的关系,不关心底层如何实现. 顺序表.链表:物理结构,他是实现一个结构实际物理地址上的结构.比如顺序表就是用数组实现.而链表用指针完成主要工作.不同的结构在不同的场景有不同的区别. 对于java来说,大家都知道List接口类型,这就是逻辑结构,

数据结构二叉树构造及遍历详解

前言 最近学到了二叉树,就学着将二叉树构造,并尝试三种遍历操作.本次主要使用递归,回头会整理非递归的方法. 定义二叉树 1 typedef struct BinaryTree 2 { 3 TelemType data; 4 struct BinaryTree *lchild; 5 struct BinaryTree *rchild; 6 }*Node,node; 其中要注意Node是结构体指针,这样定义以后使用会方便很多. 构造二叉树 1 Node CreatTree() 2 { 3 Node

Python实现的数据结构与算法之快速排序详解

一.概述 快速排序(quick sort)是一种分治排序算法.该算法首先 选取 一个划分元素(partition element,有时又称为pivot):接着重排列表将其 划分 为三个部分:left(小于划分元素pivot的部分).划分元素pivot.right(大于划分元素pivot的部分),此时,划分元素pivot已经在列表的最终位置上:然后分别对left和right两个部分进行 递归排序. 其中,划分元素的 选取 直接影响到快速排序算法的效率,通常选择列表的第一个元素或者中间元素或者最后一