AVL树C语言实现

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

AVL树介绍

AVL树是带有平衡条件的二叉查找树。这个平衡条件必须容易保持,而且它必须保证树的高度是O(logN)。AVL树其每个节点的左子树和右子树高度最多差1(空树的高度为-1),每个节点保留其高度信息。下图中,左边的图是AVL树,而右边的不是。

节点插入

当对一个AVL树插入节点后,只有那些从插入节点到根节点的路径上的节点的平衡可能被改变,因为这些节点的子树可能发生变化。当我们沿着这条路径上行到根并更新平衡信息时,我们可以找到第一个节点,它的新平衡破坏了AVL条件。下面指出如何调整这个节点。

假设必须重新平衡的节点叫做A。由于任意节点最多有两个孩子,因此高度不平衡时,A点的两个子树的高度差2.容易看出,这种不平衡可能出现在下面四种情况中:

1):对A的左儿子的左子树进行了一次插入,可通过一次单旋调整;

2):对A的左儿子的右子树进行了一次插入,可通过一次双旋调整

3):对A的右儿子的左子树进行了一次插入,可通过一次双旋调整

4):对A的右儿子的右子树进行了一次插入,可通过一次单旋调整;

其中,情形1和4是关于A点的镜像对称,情形2和3也是关于A点的镜像对称。单旋较简单,如示例图1所示:首先找到不满足平衡条件的节点(节点3),然后在该节点与该节点的儿子之间(节点4)进行一次单选操作即可。


图1:情形4所进行的单旋转操作

对于双旋,其实用一句话就可以简单概括双旋:假如A点是破坏平衡条件的第一个需要调整的节点,那么双旋发生的是:首先在A的儿子和孙子之间做一次单旋,然后在A和它的新儿子之间再做一次单旋。如示例图2所示,插入节点14之后,节点6不在满足平衡条件。因为是在6的右儿子的左子树进行插入,所以需要进行一次右左双旋。首先在节点6的儿子(节点15)和孙子(节点7)之间进行一次右旋,得到中间结果,然后将节点6和其新儿子(节点7)之间进行左旋,得到最终结果。右左双旋也是同样的道理。



图2 双旋操作

节点删除

回顾一下对于一般的二叉查找树是怎样进行remove操作的。先根据二叉树的性质找到应该删除的结点t(如果有的话):如果t是个叶子结点,直接delete就好;如果它只有一颗非空的子树,那么就让这颗子树继承被删除结点的位子;而如果它有两颗非空的子树,就在右子树X中找到值最小的结点s,将s的data(值)写到t中,再在X中删除s(因为s的左子树一定为空,否则它就不是X中最小的了。另外,当然也可以在左子树中找值最大的结点)


对于AVL树的删除操作,可概括为如下几种情况:

首先在树中搜寻是否有节点的元素值等于需要删除的元素。如未搜索到,直接返回。否则执行以下操作。

(1)  要删除的节点是当前根节点T。

            如果左右子树都非空。在高度较大的子树中实施删除操作。分以下两种情况:

                    A、左子树高度大于右子树高度,将左子树中最大的那个元素赋给当前根节点,然后删除左子树中元素值最大的那个节点。

                    B、左子树高度小于右子树高度,将右子树中最小的那个元素赋给当前根节点,然后删除右子树中元素值最小的那个节点。

          如果左右子树中有一个为空,那么直接用那个非空子树或者是NULL替换当前根节点即可。

(2)  要删除的节点元素值小于当前根节点T值,在左子树中进行删除。

            递归调用,在左子树中实施删除。

            这个是需要判断当前根节点是否仍然满足平衡条件,如果满足平衡条件,只需要更新当前根节点T的高度信息。 否则,需要进行旋转调整:

            如果T的右子节点的左子树的高度大于 T的右子节点的右子树的高度,进行相应的双旋转。否则进行单旋转。

(3)  要删除的节点元素值大于当前根节点T值,在右子树中进行删除。如果T的左子节点的右子树高度大于左子节点的左子树高度,进行双旋,否则进行单旋。过程和(2)类似

(4)  回朔被删除节点到根的路径上的其他节点,检查其平衡因子是否满足要求。

下面通过例子简要说明:

例1:如上图,若删除节点8,则其根节点9仍满足高度平衡,因此不需要旋转,简单调整元素9的平衡因子。然后再删除12,此时符合情况(3),11元素为当前的根T,令它的左子树为S,检查S的左子节点的高度HL与右子节点的高度HR,上图中可以看出HL = -1,HR = 0,所以符合双旋条件(HL < HR)。

例2:如果直接在原图上删除12,那么当前的根仍是11,但此时,11的平衡因子被打破,仍然符合情况(3),此时T的左子树为S,S的左子树高度HL = 0,S的 右子树高度为0,此时不满足双旋条件,故在根12处单旋。

代码实现

头文件:AvlTree.h

typedef int ElementType;

#ifndef _AVLTREE_
#define _AVLTREE_

struct AvlNode;
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;

AvlTree MakeEmpty( AvlTree T );
Position Find( ElementType X, AvlTree T );
Position FindMin( AvlTree T );
Position FindMax( AvlTree T );
AvlTree Insert( ElementType X, AvlTree T );
AvlTree Remove( ElementType X, AvlTree T );
ElementType Retrieve( Position P );
void PrintTree(AvlTree T);
AvlTree Remove(const ElementType X, AvlTree T);

#endif

实现文件:AvlTree.c

#include "AvlTree.h"
#include <stdio.h>
#include <stdlib.h>

struct AvlNode
{
    ElementType Element;
    AvlTree Left;
    AvlTree Right;
    int Height;
};

AvlTree MakeEmpty( AvlTree T )
{
    if (T != NULL)
    {
        MakeEmpty(T->Left);
        MakeEmpty(T->Right);
        free(T);
    }
    return NULL;
}

Position Find( ElementType X, AvlTree T )
{
    if (T == NULL)
        return NULL;
    if (X < T->Element)
        return Find(X, T->Left);
    else if (X > T->Element)
        return Find(X, T->Right);
    else
        return T;
}

Position FindMin( AvlTree T )
{
    if (T == NULL)
        return NULL;
    /*if (T->Left == NULL)
        return T;
    else
        return FindMin(T->Left);*/
    while (T->Left != NULL)
        T = T->Left;
    return T;
}

Position FindMax( AvlTree T )
{
    if (T == NULL)
        return NULL;
    /*if (T->Right == NULL)
        return T;
    else
        return FindMax(T->Right);*/
    while (T->Right)
        T = T->Right;
    return T;
}

static int Height( Position P )
{
    if (P == NULL)
        return -1;
    else
        return P->Height;
}

static int Max( int Lhs, int Rhs )
{
    return Lhs > Rhs ? Lhs : Rhs;
}

static Position SingleRotateWithLeft( Position K2)
{
    Position K1;
    K1 = K2->Left;
    K2->Left = K1->Right;
    K1->Right = K2;
    K2->Height = Max(Height(K2->Left), Height(K2->Right)) + 1;
    K1->Height = Max(Height(K1->Left), Height(K1->Right)) + 1;
    return K1;
}

static Position SingleRotateWithRight( Position K1)
{
    Position K2 = K1->Right;
    K1->Right = K2->Left;
    K2->Left = K1;
    K1->Height = Max(Height(K1->Left), Height(K1->Right)) + 1;
    K2->Height = Max(Height(K2->Left), Height(K2->Right)) + 1;
    return K2;
}

/* Do the left-right double rotation */
static Position DoubleRotateWithLeft( Position K3 )
{
    K3->Left = SingleRotateWithRight(K3->Left);
    return SingleRotateWithLeft(K3);
}

/* Do the right-left double rotation */
static Position DoubleRotateWithRight( Position K1 )
{
    K1->Right = SingleRotateWithLeft(K1->Right);
    return SingleRotateWithRight(K1);
}

AvlTree Insert( ElementType X, AvlTree T )
{
    if (T == NULL)
    {
        T = (AvlTree)malloc(sizeof(struct AvlNode));
        if (T == NULL)
        {
            printf("Out of space!!\n");
            return T;
        }
        else
        {
            T->Left = T->Right = NULL;
            T->Element = X;
        }
    }
    else if (X < T->Element)
    {
        T->Left = Insert(X, T->Left);
        if (Height(T->Left) - Height(T->Right) == 2)
        {    
            //插入之后,引起不平衡,若是在左儿子的左子树中插入,即左-左,只需左单旋即可;
            if (X < T->Left->Element)
                T = SingleRotateWithLeft(T);
            else
            //若是在左儿子的右子树中插入,即左-右,需要左双旋
                T = DoubleRotateWithLeft(T);
        }
    }
    else if (X > T->Element)
    {
        T->Right = Insert(X, T->Right);
        if (Height(T->Right) - Height(T->Left) == 2)
        {
            if (X > T->Right->Element)
                T = SingleRotateWithRight(T);
            else
                T = DoubleRotateWithRight(T);
        }
    }
    T->Height = Max(Height(T->Left), Height(T->Right)) + 1;
    return T;
}

ElementType Retrieve( Position P )
{
    return P->Element;
}

void PrintTree(AvlTree T)
{
    if (T != NULL)
    {
        PrintTree(T->Left);
        printf("%3d", Retrieve(T));
        PrintTree(T->Right);
    }
}

AvlTree Remove(ElementType X, AvlTree T)
{
      if(T == NULL)
          return NULL;//没有找到要删除的值,do nothing
      if(X < T->Element)
      {
          T->Left = Remove(X, T->Left);
          if(Height(T->Right)-Height(T->Left)==2)
          {
              //右子树比左子树高2,那么在删除操作之前右子树比左子树高1,
             //也就是说T的右子树必然不为空,甚至必然有非空子树(高度至少为1).
             AvlTree s = T->Right;
             if(Height(s->Left)>Height(s->Right))
                 T = DoubleRotateWithRight(T);//右双旋转
             else
                 T = SingleRotateWithRight(T);//右单旋转
         }
         else
             //不需要调整就满足平衡条件的话,只需要重新计算其高度就好
             T->Height=Max(Height(T->Left),Height(T->Right))+1;
     }
     else if(X>T->Element)
     {

         T->Right = Remove(X,T->Right);
         if(Height(T->Left)-Height(T->Right)==2)
         {
             AvlTree s=T->Left;
             if(Height(s->Right)>Height(s->Left))
                 T = DoubleRotateWithLeft(T);//左双旋转
             else
                 T = SingleRotateWithLeft(T);//左单旋转
         }
         else
             T->Height=Max(Height(T->Left),Height(T->Right))+1;
     }
     else
     {
         if(T->Left&&T->Right)         //T的左右子树都非空,把Remove操作转移到只有一个非空子树的结点或者叶子结点上去
         {
             if( Height(T->Left) > Height(T->Right) )
             //把Remove操作往更高的那颗子树上转移
             {
                 //左子树中的最大值
                 T->Element=FindMax(T->Left)->Element;
                 T->Left = Remove(T->Element,T->Left);
             }
             else
             {
                 //右子树中的最小值
                 T->Element=FindMin(T->Right)->Element;
                 T->Right = Remove(T->Element,T->Right);
             }
         }
         else
         {
             AvlTree oldnode = T;
             T=T->Left?T->Left:T->Right;
             free(oldnode);
         }
     }
    return T;
}


AVL(C语言实现 AVL的相关操作,包括插入,删除,查找,调整。(C语言实现 阅读详情

相关推荐

Avl的基本操作(c语言实现

#include #include typedef struct AvlNode *Position; typedef struct AvlNode *AvlTree; typedef int ElementType; struct AvlNode{ ElementType Element; AvlTree Left; AvlTree Right; int Height; }AvlNo

王鹏的博客 3824

AVL的C语言实现

AVL的C语言实现

AVLC语言完整实现

AVL的介绍见http://blog.csdn.net/pngynghay/article/details/22443525,本文给出的是AVL的一种实现。 采用非递归方式,效率较好,经过常规测试。   #include #include #include #include #include typedef enum { EH = 0, LH = 1, RH = -1

IT_Linux 2414

AVL的c语言实现代码(添加和删除)

这个代码是关于AVL的添加和删除的实现

C 语言实现 AVL

一、平衡二叉简介     平衡二叉又称 AVL,其具有如下两个性质: 必须是二叉; 必须是一颗空或者其左右子的高度只差不超过 1。     平衡二叉实现主要是为了避免普通二叉查找在极端情况下(全部节点只有左孩子或者全部节点只有右孩子)会像链表那样影响性能。 二、AVL 自平衡 #include <stdio.h> #include <stdlib.h> #include <string.h> #include "AVLTree.h" #defi

SauryN的博客 2517

平衡二叉排序AVL(C语言实现

本文详细介绍了平衡二叉排序中的AVL,对失衡类型和不同失衡类型的调整方式做了细致的描写,并用C语言实现AVL

zhao_Tao_WA的博客 1151

用C语言实现的——一个完整的AVL的交互式系统

用C语言实现的——一个完整的AVL的交互式系统,支持查找、插入、删除、查找指定节点的前驱和后继节点、形展示、层次展示、文件存储等功能。

2401_84643729的博客 1661

二叉平衡实现(c语言版)

c语言实现二叉平衡实现代码

2501_92907982的博客 217

AVL实现(C语言)

这段代码实现AVL的基本操作,包括插入、查找、中序遍历和销毁。每行代码都有注释,解释了代码的作用。这个实现假设中没有重复的值。在实际应用中,可能需要处理重复值和其他边界情况。自旋原理是指在插入或删除操作后,AVL通过一系列的旋转操作来恢复的平衡。以下是AVL的C语言实现,包括插入、删除、遍历、查找和销毁功能,每行代码都有注释。

qq_40844444的博客 439

AVL实现(C语言实现)

最近恶补数据结构,不过抱着小侄女实在复习不进去。。。这才复习完 当时对于平衡就没有一个系统的了解  具体的感念就不贴了,仔细说一说如何调整平衡二叉 如果插入破坏了原有的平衡,“麻烦结点”在发现者右子的右边,因而叫 RR 插入,需要RR 旋转(右单旋) 做如下调整 “麻烦结点”在发现者左子的左边,因而叫 LL 插入,需要LL 旋转(左单旋)

rainxbow的专栏 1059

AVL详解及其C语言实现

本文讲述AVL、应用场景及其C语言实现AVL的全称是Adelson-Velsky and Landis Tree,简称AVLAVL是一种自平衡的二叉搜索,其特点是在每次插入或删除操作之后,都会自动调整的结构,以确保的高度保持在尽可能小的状态。这种调整是通过旋转操作来实现的,以保持的平衡性。在AVL中,每个节点都维护了一个平衡因子,即其左子的高度减去右子的高度。平衡因子的值只能为-1、0或1。

SEU123WW的博客 731

AVL(一)之 图文解析 和 C语言实现

概要 本章介绍AVL。和前面介绍"二叉查找"的流程一样,本章先对AVL的理论知识进行简单介绍,然后给出C语言实现。本篇实现的二叉查找是C语言版的,后面章节再分别给出C++和Java版本的实现。 建议:若您对"二叉查找"不熟悉,建议先学完"二叉查找"再来学习AVL。 目录 1. AVL的介绍 2. AVL的C实现 3. AVL的C实现(完整源码) 4. AVL

ProgrammingRing的专栏 9429

AVLC语言实现

AVL(一)之 图文解析 和 C语言实现

个人公众号: 码小菜 671

c 编程语言 ,使用C编程语言实现AVL

本文将介绍AVL及其插入、删除操作,最后使用C编程语言实现基于平衡因子(balance factor)的AVL。什么是AVLAVL(AVL tree)是前苏联计算机科学家Adelson-Velsky和Landis发明的一种自平衡二叉查找(self-balancing binary search tree)。它有两大属性,一个是继承自二叉查找的查找属性(binary search pr...

weixin_35715235的博客 225

用C语言实现一个AVL

AVL是一种平衡二叉,它的每个节点的左右子的高度相差不超过1。这个性质使得AVL插入和删除操作的时间复杂度能够保持在对数级别,这与二叉搜索相比具有较高的效率。 下面是一个用C语言实现AVL的示例代码: ``` #include <stdio.h> #include <stdlib.h> typedef struct AVLTreeNode { int key...

weixin_35755823的博客 205

数据结构之 AVL(平衡二叉)(C语言实现

AVL(平衡二叉)1. AVL定义和性质AVL(Adelson-Velskii和Landis发明者的首字母)时带有平衡条件的二叉查找。二叉查找的性能分析: 在一颗左右子高度平衡情况下,最优的时间复杂度为O(log2nlog_2{n}),这与这半查找相同; 在一个只有右子的二叉中,最差的时间复杂度会脱变为线性查找O(n)。 二叉查找实现:二叉查找的C语言实现由于二叉查找存在以

men_wen的博客 5437

AVL及C语言实现

概念   平衡二叉(Balanced binary tree)是由苏联数学家Adelson-Velskii and Landis于1962年首先提出的,所以又称为AVL。 定义:平衡二叉或为空,或满足如下性质的二叉:  (1)本身首先是一棵二叉搜索   (2)左右子深度之差的绝对值不超过1;   (3)左右子仍然为平衡二叉. 平衡因子BF=左子深度-右子深度.

IT_Linux 9909

AVL--C语言实现

/************************************************************************ *                        AVL demo程序                                  * Version:1.0    实现insert函数                             

nizqsut的专栏 353
上一篇: 二叉查找树c语言实现
下一篇: 散列表
红桃Ace
博客等级 码龄15年 5粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值