AVL树原理思想及其实现

AVL树的构造实现 今天接触的是平衡二叉查找树,对于AVL树来说相比之前的数据结构稍微多了一些需要注意的地方,照例在此总结总结让自己巩固一二。 首先是使用AVL树的动机: 我们知道AVL树本质上是排序二叉树的一类特例,回顾一下,对于排序二叉树的定义考虑使用归纳定义: ①、空树是二叉查找树; ②、若p和q都是二叉查找树,而root是一个“关键字大于p上所有结点的关键字,并小于q上所有结点的关键字”的元素 阅读详情

AVL树,一种平衡搜索二叉树,是BST(Binary Search Tree)二叉查找树的一种,实际上是在BST搜索树上增加了平衡条件,所谓的平衡条件指的是树中的每个结点的左孩子与右孩子的高度之差不大于1。既然是一种BST树,那么它肯定满足BST的一般性质。在计算机科学领域,二叉搜索树(BST),有时也称作有序的或者排序好的二叉树,是一种特殊类型的容器。它允许快速的查找,增加,删除结点,可以被用作动态集合的生成。BST树以有序的键值保存,这样在查找或者其他操作时可以利用二分查找原理。在了解AVL树之前,先了解下二叉查找树BST的一般性质:

1. 在一棵二叉查找树,执行查找、插入、删除等操作的时间复杂度为O(lgn)。

2. 一棵具有n个结点的BST生成线性链表,则这些操作最坏情况运行时间为O(n)。

而AVL树,则是对BST树操作的增强,对树的操作最好与最坏时间均为O(lgn),在动态生成AVL树时,如果结点的左右孩子深度之差大于1,则需要根据一定的规则来调整树,这个被称为树的旋转。由于二叉树平衡高度大于1(即需要调整的条件),从调整结点开始的子树至少深度为3(包括根结点),而从根结点到插入后的叶子结点路径,每一层都有2个方向,而2层结点则有4种可能性,即LL,RR,LR,RL等这4种情形。比如LL左平衡型,指的是从待需要调整的子树根结点开始,其左边孩子的深度比右边孩子的叶子结点大2,利用扁担原则,需要向右边平衡。下面简单用图示来说明这几种类型的调整规则:

 

 


//============================================================================
// Name        : AVL.h
// Author      : @CodingGeek
// Version     : V1.0
// Copyright   :
// Description : AVL平衡搜索二叉树代码实现
//============================================================================

#ifndef AVL_H_
#define AVL_H_

typedef int KEY_TYPE;

/* AVL树结点数据结构 */
typedef struct AVL
{
    KEY_TYPE key;
    int height;
    struct AVL *lchild;
    struct AVL *rchild;
} AVL;

int getHeight(AVL* node); //获取结点深度

AVL* LL_Rotate(AVL* k2);  //LL类型
AVL* RR_Rotate(AVL* k2);  //RR类型
/*
 Return which the root pointer should point to
 */
AVL* LR_Rotate(AVL* k3); //LR类型
AVL* RL_Rotate(AVL* k3); //RL类型


AVL* insertNode(AVL* root, KEY_TYPE key); //插入结点
AVL* deleteNode(AVL* root, KEY_TYPE key); //删除结点
void print_tree(AVL *node); //打印AVL树结点

#endif /* AVL_H_ */
//============================================================================
// Name        : AVL.cpp
// Author      : @CodingGeek
// Version     : V1.0
// Copyright   :
// Description : AVL平衡搜索二叉树C代码实现
//============================================================================

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

AVL* makeNode(KEY_TYPE key)
{
    AVL* p_avl = (AVL*)malloc(sizeof(AVL));
    p_avl->key = key;
    p_avl->lchild = NULL;
    p_avl->rchild = NULL;
    p_avl->height = 1;
    return p_avl;
}

int getHeight(AVL* node)
{
    return (node == NULL)? 0: node->height;
}

inline int max(int a, int b)
{
    return a > b ? a : b;
}

/* LL(Y rotates to the right):

        k2                   k1
       /  \                 /  \
      k1   Z     ==>       X   k2
     / \                       /  \
    X   Y                    Y    Z
*/

AVL* LL_Rotate(AVL* k2)
{
    AVL* k1 = k2->lchild;
    k2->lchild = k1->rchild;
    k1->rchild = k2;
    k2->height = max(getHeight(k2->lchild), getHeight(k2->rchild)) + 1;
    k1->height = max(getHeight(k1->lchild), k2->height) + 1;
    return k1;
}

/* RR(Y rotates to the left):

        k2                           k1
       /  \                         /  \
      X    k1         ==>          k2   Z
          /  \                    /  \
         Y    Z                 X    Y
 */
AVL* RR_Rotate(AVL* k2)
{
    AVL* k1 = k2->rchild;
    k2->rchild = k1->lchild;
    k1->lchild = k2;
    k2->height = max(getHeight(k2->lchild), getHeight(k2->rchild)) + 1;
    k1->height = max(getHeight(k1->rchild), k2->height) + 1;
    return k1;
}

/* LR(B rotates to the left, then C rotates to the right):

      k3                       k3                       k2
     /  \                     /  \                     /  \
    k1   D                   k2   D                  k1   k3
   /  \         ==>         /  \        ==>          / \   / \
  A    k2                  k1   C                  A  B  C   D
       /  \               /  \
      B    C            A    B

*/

AVL* LR_Rotate(AVL* k3)
{
    k3->lchild = RR_Rotate(k3->lchild);
    return LL_Rotate(k3);
}


/* RL(D rotates to the right, then C rotates to the left):

       k3                           k3                         k2
      /  \                         /  \                       /  \
     A    k1                      A    k2                   k3   k1
          /  \       ==>              /  \         ==>      / \   / \
         k2   B                     C    k1                A  C  D   B
        /  \                             /  \
       C    D                           D    B

 */

AVL* RL_Rotate(AVL* k3)
{
    k3->rchild = LL_Rotate(k3->rchild);
    return RR_Rotate(k3);
}

AVL* insertNode(AVL* root, KEY_TYPE key)
{
    if (root == NULL)
    {
        return makeNode(key);
    }

    if (root->key == key)
    {
        return root;
    }
    else if (key < root->key)
    {
        root->lchild = insertNode(root->lchild, key);
    }
    else //key >= root->key
    {
        root->rchild = insertNode(root->rchild, key);
    }

    root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;

    if (getHeight(root->lchild) - getHeight(root->rchild) == 2)
    {
        if(key < root->lchild->key)
        {
            root = LL_Rotate(root);
        }
        else
        {
            root = LR_Rotate(root);
        }
    }
    else if (getHeight(root->rchild) - getHeight(root->lchild) == 2)
    {
        if(key > root->rchild->key)
        {
            root = RR_Rotate(root);
        }
        else
        {
            root = RL_Rotate(root);
        }
    }
    return root;
}


AVL* deleteNode(AVL* root, KEY_TYPE key)
{
    if (root == NULL)
    {
        return NULL;
    }

    if (key == root->key)
    {
        if(root->rchild == NULL)
        {
            AVL* temp = root;
            root = root->lchild;
            free(temp);
            return root;
        }
        else
        {
            AVL* temp = root->rchild;
            while(temp->lchild)
            {
                temp = temp->lchild;
            }
            root->key = temp->key;
            root->rchild = deleteNode(root->rchild, temp->key);
        }
    }
    else if (key < root->key)
    {
        root->lchild = deleteNode(root->lchild, key);
    }
    else
    {
        root->rchild = deleteNode(root->rchild, key);
    }

    root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;

    if (getHeight(root->rchild) - getHeight(root->lchild) == 2)
    {
        if (getHeight(root->rchild->rchild) >= getHeight(root->rchild->lchild))
        {
            root = RR_Rotate(root);
        }
        else
        {
            root = RL_Rotate(root);
        }
    }
    else if (getHeight(root->lchild) - getHeight(root->rchild) == 2)
    {
        if (getHeight(root->lchild->lchild) >= getHeight(root->lchild->rchild))
        {
            root = LL_Rotate(root);
        }
        else
        {
            root = LR_Rotate(root);
        }
    }
    return root;
}

void print_tree_indent(AVL *node, int indent)
{
    for (int ix = 0; ix < indent; ix++)
    {
        printf(" ");
    }
    if (node == NULL)
    {
        printf("Empty Child\n");
    }
    else
    {
        printf("Node: %d; Height: %d\n", node->key, node->height);
        print_tree_indent(node->lchild, indent + 4);
        print_tree_indent(node->rchild, indent + 4);
    }
}

void print_tree(AVL *node)
{
    print_tree_indent(node, 0);
}
//============================================================================
// Name        : AVLTree.cpp
// Author      : @CodingGeek
// Version     :
// Copyright   : V1.0
// Description : AVL平衡搜索二叉树代码实现
//============================================================================
#include <stdio.h>
#include "AVL.h"

int main(int argc, char* argv[])
{
    srand(time(NULL));
    const int num = 20;
    int *pArr = (int*)malloc(sizeof(int) * num);

    for (int i = 0; i < num; i++)
    {
        pArr[i] = rand() % 100;
        printf("%d ", pArr[i]);
    }
    printf("\n=======================\n");
    AVL *root = NULL;
    for (int i = 0; i < num; i++)
    {
        root = insertNode(root, pArr[i]);
    }
    printf("AVL Tree:\n"); 
    print_tree(root); 
    int input = 0x0; 
    do 
    { 
        printf("\nPlease input the value you want to delete:\n"); 
        scanf("%d",&input);
        root = deleteNode(root, input); 
        printf("\nAfter delete %d:\n",input); 
        print_tree(root); 
    }while (getHeight(root)); 
    printf("\n"); 
    return 0;
}

  





C++版【AVL树的模拟实现】 希望大家可以自行写出遍历操作、求树的高度、求树的节点个数等成员函数,需要注意的是,利用递归来完成的,都需要写个子函数,然后封装一下子函数.大家感兴趣,可以自行查阅删除操作后续会实现红黑树,红黑树那里会模拟实现一下map和set。 阅读详情

相关推荐

【无线通信】射频杂散(RF Spurious Emissions)

射频杂散(RF Spurious Emissions)是指在无线通信系统中,除了在指定频率范围内的预期信号之外,任何不需要的或非预期的射频信号。这些杂散信号可能会干扰其他通信系统,降低系统性能,并违反无线电通信法规。射频杂散通常包括谐波、次谐波、互调产物和其他非线性失真所产生的信号。

qq_38801607的博客 5427

平衡二叉树(AVL树)

平衡二叉树(AVL树),是一种有序树,因为普通的二叉树如果添加的节点有序,查询效率会与数组无异,而AVL树改变了它的弊端,会实时调整树的高度,使它左右子树的树高之差的绝对值不会大于1。下面给出使用java代码完成的AVL树:import java.util.LinkedList; import java.util.Queue; class AVLTree { private int n; ...

hldfight 706

保姆级教程:手把手教你从ENSEMBL官网下载GRCh38/GRCh37的GTF注释文件(附网址规律总结)

本文提供从ENSEMBL官网下载GRCh38/GRCh37的GTF注释文件的详细教程,包括路径解析、版本号确定和下载命令示例。特别解析了GRCh37的特殊存储结构,并分享批量下载、文件校验等高级技巧,帮助生物信息学研究者高效获取基因组注释文件。

weixin_29289821的博客 204

有序表之AVL树

数据库中最重要的基础是索引,索引为什么能被建立起来,因为能建立索引的字段都是可以排序的,(任何字符串都可以排序)只是我们平时感受不深。 排序是如何帮助加速找数据库里的东西的呢? 在数据库里存数据的方式真的有可能是有顺序的。数据库里面硬盘结构可能就是有顺序的。底层数据写在硬盘上是顺序的,在底层数据之上建出一颗索引树。 搜索二叉树单纯的加数据,找数据很容易,所以搜索二叉树本身就可以支持索引了,增删改查都在树上玩。 但问题是,在最坏情况下,这棵树会退化成为链表。 这个时候就引出了平衡搜索二叉树的概念:一棵树先保

Harrison的学习博客 1246

中科蓝讯AB536X/AB892X芯片开发避坑指南:Downloader配置中那些容易忽略的细节

本文详细解析中科蓝讯AB536X/AB892X芯片开发中Downloader配置的关键细节,包括软开关机实现、触摸灵敏度调试、量产校频等常见问题。特别针对无PR口芯片的替代方案、触摸参数优化、校频流程等易忽略环节提供实用解决方案,帮助开发者规避量产风险,提升开发效率。

weixin_30687051的博客 476

数字IC后端设计实现OCC(On-chip Clock Controller)电路介绍及时钟树综合案例

数字IC后端设计实现OCC(On-chip Clock Controller)电路介绍及时钟树综合案例

weixin_37584728的博客 4740

数据结构:AVL树的实现和全部图解

AVL树的模拟实现

海绵宝宝de派小星的博客 2986

Shader Graph入门

Shader Graph 简介

zaizai1007的博客 1万+

AVL树的理解和实现[C++]

首先,我们定义AVL树的节点结构//值//该节点的左孩子//该节点的右孩子//该节点的父节点int _bf;// balance factor(平衡因子):_kv(kv), _bf(0){}

Q741_147的博客 629

计算机组成与系统结构(第三版) 袁春风主编 课后习题答案讲解 第一、二章 计算机系统概述 数据的机器级表示

计算机组成与系统结构(第三版) 袁春风主编 课后习题答案讲解 第一、二章 计算机系统概述 数据的机器级表示

qq_73523062的博客 2093

基于OpenAI Agents构建多智能体工作流:从原理到实战

多智能体系统(Multi-Agent System)是人工智能领域的重要分支,它通过多个智能体(Agent)的协作与交互,解决单一智能体难以处理的复杂任务。其核心原理在于将任务分解、分配与协调,每个智能体具备特定能力,通过通信机制实现信息共享与决策协同。在工程实践中,多智能体框架的价值在于提升任务处理效率、增强系统鲁棒性,并支持模块化开发。典型的应用场景包括自动化工作流编排、复杂问题求解以及人机协同交互。本文以OpenAI Agents SDK为例,深入探讨如何利用其提供的智能体(Agent)、会话(Ses

weixin_28725959的博客 603

AVL树详解(实现AVL树,涉及单旋和双旋,有图解,超详细)

AVL树详解(实现AVL树,涉及单旋和双旋,有图解,超详细)

HBINen的博客 3902

电化学-NanoStat-开源系统的使用说明

本文主要介绍了NanoStat开源系统的使用方法,从硬件打板、设备组装、软件安装3个层次进行了详细说明。整个流程根据作者提供的视频能够很好的完成,不需要太多的技术,对刚入门的新手是一个不错的练手项目。其次软件还有很大的优化空间,能够进一步提高系统的精度,对之后类似恒电位仪系统的开发也有很大的借鉴意义。

分享技术笔记,希望对大家能够有一定的帮助,同时也通过归纳总结提升自己的个人能力。 2003

一文吃透二叉树、完全平衡树、红黑树原理及C语言实现

二叉树是一种树形数据结构,它的每个节点最多有两个子节点,分别称为左子节点和右子节点。这使得二叉树的结构相对简单且规则,易于理解和操作。根节点:是二叉树的起始节点,它没有父节点,就像是大树的根基,所有其他节点都从根节点衍生出来。叶子节点:也叫终端节点,是没有子节点的节点,它们位于二叉树的最底层,就像树枝的末梢。度:指一个节点拥有的子树数目。二叉树中节点的度最大为 2,即每个节点最多有两个子节点。深度:从根节点到最远叶子节点的最长路径上的节点数,它反映了二叉树的层次深度。

李熠专用博客_白帽子一枚,人称低危终结者。免费收徒,有意者私信!!! 999

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

SkipList跳表基本原理

(2012-10-17 19:04:14) 转载▼ 标签: 杂谈 分类: 技术荟萃 为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等。 想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树 出来吗? 很难吧,这需要时间,要考虑很多细节,要参考一堆算

jarry_gao的专栏 515

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

一篇搞定AVL树原理及模拟实现

AVL树的介绍,插入的旋转思想,代码实现及性能分析

2301_77509762的博客 2419

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

AVL树的原理及其实现

回顾我们对于二叉搜索树的了解,二叉搜索树的效率跟树的高度成反比。而且,数据插入的随机性导致普通的二叉搜索树甚至可能退化成一条“单链表”,这样的结构查找起来时间复杂度直奔O(N),这无疑是我们不想看到的。我们希望,无论数据怎么插入,二叉搜索树的结构都应该保持平衡,即看起来更加接近于完全二叉树或者满二叉树AVL树因此诞生。

稻草人敲代码的博客 1413

【C++】:AVL树的深度解析及其实现

上一篇文章对其底层都是按照二叉搜索树来实现的,但是二叉搜索树有其自身的缺陷,假如往树中插入的元素有序或者接近有序,二叉搜索树就会退化成单支树,时间复杂度会退化成O(N),因此map、set等关联式容器的底层结构是对二叉树进行了平衡处理,即采用平衡树来实现。本篇文章介绍的就是平衡树之一的:AVL树。注意:本篇文章AVL树实现的 key_value 模型。因为实际上 map/set 的底层并不是用AVL树封装的,而是用红黑树(下一篇文章),

2301_77900444的博客 2192

AVL树及其C++实现

AVL树(高度平衡二叉树)的介绍及其C++实现

Nim的辙迹 4565

[C++] 剖析AVL树功能的实现原理

详细讲解AVL树功能的代码底层实现,包括:插入,删除,旋转等。

kevin_blog 1648

AVL树(包括其代码实现以及思想过程)

AVL树又名自平衡的二叉搜索树,本文将逐步介绍其形成过程和原理思想``当我们遇到如下情况的二叉树搜索树的时候可以看出当我们需要遍历或者访问里面的数据变量时,它的时间复杂度就从O(log N)变成了O( N ),从树结构的操作变成了链表操作。这时候就需要用一种方式来控制其高度上的变化来维持这段树结构。两位苏联数学家G.M.Adelson-Velsky和E.M.Landis在1962年发明了AVL树(又名自平衡的二叉搜索树)。它时最先被发明的一种自平衡二叉查找树。

make_day_day_up的博客 1867

C++中AVL树的底层逻辑原理及其实现原理和过程

本篇主要讲解了AVL树的底层原理和实现原理及如何实现,相信大家看完一定会收获满满!~~~~~~

2302_80214413的博客 1398

AVL树原理详解与实现(附代码)

上一篇文章讲了二叉搜索树,但是它会在极端情况下退化为链表,造成查找时间复杂度退化为O(N)O(N)O(N),那么怎样才能让它不退化为链表呢?这篇文章告诉你,快来看看把! 文章目录1. 平衡二叉树的定义2. AVL树的调整3. AVL树的实现4. 完整代码,带测试程序 1. 平衡二叉树的定义 平衡说的是树的高度平衡,平衡二叉树可以这么定义: 一颗空树 如果不是空树,那么它的左子树和右子树都是平衡二叉树,且左右子树的高度差绝对值不超过1 树的高度怎么定义? 如果是空树,高度为0 如果不是空树,那高度就.

张凯 1万+

AVL树实现及其性能分析

AVL树的提出: 二叉搜索树虽然可以缩短查找的效率, 但如果数据有序, 或者接近有序, 二叉搜索树将退化为单支树, 查找元素相当于在顺序表中搜索元素, 效率低下. 二叉搜索树实现及其性能分析 由此,1962年G.M.Adelson-Velskii和E.M.Landis两位俄罗斯数学家提出平衡二叉搜索树的方法: 当向二叉搜索树中插入新结点后, 保证每个结点的左右子树高度之差的绝对值不超过1(超过了则对树的结点进行相应的调整), 即可降低树的高度, 从而减少平均搜索长度. 概念: 一颗AVL树或者是空树, 或者

weixin_42562387的博客 1893

AVL树的实现

AVL树是一种高度平衡的二叉搜索树,通过平衡因子(右子树高度减左子树高度)确保任意节点左右子树高度差不超过1。插入节点时需更新路径上的平衡因子,当平衡因子变为±2时进行旋转调整(左/右单旋或左右/右左双旋)以恢复平衡。旋转操作既要保持二叉搜索树性质,又要降低子树高度。AVL树的平衡性使其查找、插入、删除操作的时间复杂度稳定在O(logN)。文中提供了AVL树节点结构定义、插入操作及右单旋的具体代码实现,展示了如何通过旋转处理不平衡情况。

2402_89035880的博客 938

STL库——AVL树

本文介绍了AVL树(自平衡二叉查找树)的基本概念和实现方法。AVL树通过控制左右子树高度差的绝对值不超过1来保持平衡,确保增删查改操作的时间复杂度为O(logN)。文章详细讲解了AVL树的结构、插入操作(包括平衡因子更新)、四种旋转方式(右单旋、左单旋、左右双旋、右左双旋)的实现原理,并提供了相应的代码实现。此外还介绍了AVL树的查找、平衡检测等功能。文章强调理解旋转操作是掌握AVL树的关键,建议通过画图加深理解。

Linux、C++、图形软件开发等。不一定每次都能写出完美的代码,但会认真搞懂每一个问题。 1152
上一篇: 堆排序算法原理及实现
下一篇: 分治法在算法设计中的运用
CodingGeek
博客等级 码龄18年 15粉丝 31原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值