AVL树详解(可视化工具)

本文深入探讨AVL树的基本概念、自平衡机制及其在C#中的具体实现,包括节点旋转、查找、插入与删除操作。通过实例演示AVL树如何保持平衡,提高搜索效率。

转自:AVL树(一)之 图文解析 和 C语言的实现(本文图片及文字描述部分转自该文)
参考:邓俊辉 的数据结构,部分图片来自该资料

代码是C#写的

AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的。
它是最先发明的自平衡二叉查找树,也被称为高度平衡树。相比于"二叉查找树",它的特点是:AVL树中任何节点的两个子树的高度最大差别为1。(树的高度:树中结点的最大层次)
在这里插入图片描述
上面的两张图片,左边的是AVL树,它的任何节点的两个子树的高度差别都<=1;而右边的不是AVL树,因为7的两颗子树的高度相差为2(以2为根节点的树的高度是3,而节点8的高度是1)。

AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。
如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。学AVL树,重点的地方也就是它的旋转算法

首先要明确的是,== 平衡二叉树是一棵二叉排序树,它的出现是为了解决普通二叉排序树(普通二叉排序树)不平衡的问题。如图,在插入结点之前首先要查找插入位置,假如要在5结点后插入,普通二叉排序树需要比较五次,而平衡二叉树只需要比较三次。假如结点规模进一步加大,效率提升也会更明显。
(图片来自https://blog.youkuaiyun.com/m0_38036210/article/details/100517125)
在这里插入图片描述

0X01 节点和树的定义

1. 节点的定义
    public class Node
    {
   
   
        public int Key;
        public Node Parent;//parent
        public Node L; //left
        public Node R; //right
        public int H; //height;

        public Node(int key, Node parent=null, Node left=null, Node right=null,int h=1)
        {
   
   
            Key = key;
            Parent = parent;
            L = left;
            R = right;
            H = h;
        }

	}
2. 树的定义
    public class AVLTree
    {
   
   
        //树的根节点
        public Node Root;
	}
3.树的高度

空的二叉树的高度是0,非空树只有一个节点根节点高度为1等等

        /// <summary>
        /// 树的高度
        /// 树的高度为最大层次。即空的二叉树的高度是0,非空树的高度等于它的最大层次(根的层次为1,根的子节点为第2层,依次类推),这里空树的高度取0,有的教材资料是-1
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public int Height(Node a)
        {
   
   
            return a == null ? 0 : a.H;
        }

        public int MaxHeight(Node a, Node b)
        {
   
   
            return a == null ? (b == null ? 0 : b.H) : (b == null ? a.H : a.H > b.H ? a.H : b.H);
        }

        public int UpdateHeight(Node a)
        {
   
   
            a.H = MaxHeight(a.L, a.R) + 1;
            return a.H;
        }      
        /// <summary>
        /// 是否平衡
        /// </summary>
        /// <param name="tree"></param>
        /// <returns></returns>
        public bool IsBalanced(Node tree)
        {
   
   
            return -2 < Height(tree.L) - Height(tree.R) && Height(tree.L) - Height(tree.R) < 2;
        }   
        /// <summary>
        /// 在左、右孩子中取更高者
        /// </summary>
        /// <param name="tree"></param>
        /// <returns></returns>
        public Node TallerChild(Node tree)
        {
   
   
            if (tree == null)
                return null;
            if (Height(tree.L) > Height(tree.R))
                return tree.L;
            else return tree.R;
        }             

0X02 单旋和双旋

前面说过,如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。

2.1 zag单旋(左旋)

如果说节点g失去平衡,g的右孩子p高度比左孩子高,且右孩子p的右孩子v高度比右孩子p的左孩子高度高,那么进行逆时针旋转进行调整高度
在这里插入图片描述
假设在子树v中插入某个节点x(虚线连接部分,其中一个节点对应x,另一个为空节点),这时候v节点是平衡的,p节点也是平衡,但是g节点不平衡,g的右孩子高度减去g的做孩子高度等于2,需要对g节点进行调整,这时候以g为轴进行逆时针旋转(左旋),调整后从a子树变为b子树;从而达到子树的平衡, 而且高度未变化,所以该子树平衡后,父节点及除子树的其他树的部分都是平衡的。

旋转代码

         /// <summary>
        /// zag 左旋转,逆时针旋转,单旋       
        ///   (逆时针旋转g)  
        ///         g          
        ///        / \         
        ///       T0  p        
        ///          / \       
        ///         T1  v      
        ///            / \     
        ///           T2  T3   
        /// 
        ///     zag单旋后:    
        ///         p(b)         
        ///       /     \      
        ///      g(a)    v(c)     
        ///     / \     / \    
        ///    T0  T1  T2  T3  
        /// 
        /// </summary>
        /// <param name="tree">非空孙辈节点</param>
        /// <returns>该树新的的根节点</returns>
        public Node Zag(Node tree)
        {
   
   
            Node v = tree, p = v.Parent, g = p.Parent, r = g.Parent;
            Node a = g, b = p, c = v;
            Node T0 = g.L, T1 = p.L, T2 = v.L, T3 = v.R;
            a.L = T0; if (T0 != null) T0.Parent = a;
            a.R = T1; if (T1 != null) T1.Parent = a; UpdateHeight(a);
            c.L = T2; if (T2 != null) T2.Parent = c;
            c.R = T3; if (T3 != null) T3.Parent = c; UpdateHeight(c);
            b.L = a; a.Parent = b;
            b.R = c; c.Parent = b; UpdateHeight(b);
            Connect
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值