数据结构之AVL树详解

数据结构之AVL树详解

什么是AVL树?

AVL树是一种自平衡的二叉搜索树,它的名称来自它的发明者Adelson-Velsky和Landis。在AVL树中,每个节点的左右子树的高度差(平衡因子)最多为1,否则需要通过旋转操作来重新平衡树。AVL树基于二叉搜索树,所以它包含了二叉搜索树的所有特性,同时也保证了树的高度始终处于对数级别,因此它的查找、插入、删除都具有$O(log{n})$的时间复杂度。

AVL树的旋转操作:

AVL树的插入和删除操作可能会使节点的平衡因子发生改变,因此需要通过旋转操作来维护平衡性。在AVL树中,定义左旋和右旋两种操作:

  1. 左旋:将一个节点的右子树变为新的父节点,同时原父节点成为新父节点的左子树

图例:

mermaid
graph LR;
A-->B;
B-->C;
C-->D;
D-->E;
subgraph 左旋示例
A-->|1|C;
C-->|2|B;
B-->|3|E;
E-->D;
end;

在上图中,进行了A节点的左旋操作,旋转后C节点成为了新的父节点,同时A节点变成了C节点的左子树,E节点成为了B节点的右子树。

  1. 右旋:将一个节点的左子树变为新的父节点,同时原父节点成为新父节点的右子树

图例:

mermaid
graph LR;
A-->B;
B-->C;
C-->D;
D-->E;
subgraph 右旋示例
C-->|1|A;
A-->|2|B;
B-->|3|D;
D-->E;
end;

在上图中,进行了C节点的右旋操作,旋转后A节点成为了新的父节点,同时C节点变成了A节点的右子树,D节点成为了B节点的左子树。

AVL树的插入操作:

AVL树的插入操作,首先需要按照二叉搜索树的规则将节点插入到正确的位置,然后判断是否需要进行旋转操作来保证平衡。

当插入一个节点后,其父节点的平衡因子发生了变化。如果插入节点的父节点的平衡因子为0,则将其修改为+1或-1(取决于插入节点是插入到左子树还是右子树)。如果插入节点的父节点的平衡因子为+1或-1,则将其修改为另一个值,并将祖先节点的平衡因子重新调整,并进行旋转操作。

插入操作的代码示例:

class AVLTree:
    def __init__(self):
        self.root = None

    def insert(self, key):
        self.root = self._insert(self.root, key)

    def _insert(self, node, key):
        if not node:
            return AVLNode(key)

        if key < node.key:
            node.left = self._insert(node.left, key)
        else:
            node.right = self._insert(node.right, key)

        node.update_height()

        if node.balance_factor > 1:
            if node.left.balance_factor < 0:
                node.left = self.left_rotate(node.left)
            node = self.right_rotate(node)
        elif node.balance_factor < -1:
            if node.right.balance_factor > 0:
                node.right = self.right_rotate(node.right)
            node = self.left_rotate(node)

        return node

AVL树的删除操作:

AVL树的删除操作比插入操作复杂一些,因为需要保证删除后的树仍是一棵AVL树。在删除节点时,需要分以下几种情况考虑:

  1. 如果删除的节点是叶子节点,则直接将其删除,然后调整其祖先节点的平衡因子

  2. 如果删除的节点只有一个子节点,将其子节点作为替代物,然后调整其祖先节点的平衡因子

  3. 如果删除的节点有两个子节点,则找到其右子树中最小的节点,用它来替换要删除的节点,然后删除那个节点。

删除操作的代码示例:

class AVLTree:
    def __init__(self):
        self.root = None

    def delete(self, key):
        self.root = self._delete(self.root, key)

    def _delete(self, node, key):
        if not node:
            return None

        if key < node.key:
            node.left = self._delete(node.left, key)
        elif key > node.key:
            node.right = self._delete(node.right, key)
        else:
            if not (node.left and node.right):
                node = node.left or node.right
            else:
                temp = node.right.get_min_node()
                node.key = temp.key
                node.right = self._delete(node.right, temp.key)

        if not node:
            return None

        node.update_height()

        if node.balance_factor > 1:
            if node.left.balance_factor < 0:
                node.left = self.left_rotate(node.left)
            node = self.right_rotate(node)
        elif node.balance_factor < -1:
            if node.right.balance_factor > 0:
                node.right = self.right_rotate(node.right)
            node = self.left_rotate(node)

        return node

示例说明:

示例1:

在AVL树中插入节点(1,2,3,4,5,6,7):

插入1:

graph LR;
    subgraph 插入1
        A(1);
        end;

插入2:

graph LR;
    subgraph 插入2
        A(1)-->B(2);
        end;

插入3:

graph LR;
    subgraph 插入3
        A(1)-->B(2);
        A-->C(3);
        end;

插入4:

graph LR;
    subgraph 插入4
        B(2)-->A(1);
        B-->D(4);
        A-->C(3);
        end;

插入5:

graph LR;
    subgraph 插入5
        B(2)-->A(1);
        B-->D(4);
        D-->C(3);
        D-->E(5);
        end;

插入6:

graph LR;
    subgraph 插入6
        B(2)-->D(4);
        A(1)-->C(3);
        D-->A;
        D-->F(6);
        A-->E(5);
        end;

插入7:

graph LR;
    subgraph 插入7
        D(4)-->B(2);
        D-->F(6);
        B-->A(1);
        F-->E(5);
        F-->G(7);
        end;

最终AVL树:

graph LR;
    subgraph AVL树
        D(4)-->B(2);
        D-->F(6);
        B-->A(1);
        B-->C(3);
        F-->E(5);
        F-->G(7);
        end;

示例2:

在AVL树中删除节点4:

graph LR;
    subgraph 删除4
        D(4)-->B(2);
        D-->F(6);
        B-->A(1);
        B-->C(3);
        F-->E(5);
        F-->G(7);
        D-.->A;
        end;

删除节点4后的AVL树:

graph LR;
    subgraph AVL树
        E(5)-->B(2);
        E-->D(6);
        B-->A(1);
        B-->C(3);
        D-->F(7);
        end;

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:数据结构之AVL树详解 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • C#常用数据结构之数组Array

    C#常用数据结构之数组Array 什么是数组 在C#中,数组是一种数据结构,它可以用于存储具有相同数据类型的多个元素。数组中的元素可以通过下标来访问,数组下标从0开始,最大下标为数组长度-1。 声明和初始化数组 声明数组 声明数组需要指定数据类型和数组名称,括号中指定数组的容量。例如,声明一个包含5个整数的数组: int[] arr = new int[5]…

    数据结构 2023年5月17日
    00
  • MySQL底层数据结构选用B+树的原因

    MySQL底层数据结构选用B+树的原因主要是因为B+树具有以下优点: 能够快速查找B+树的查找速度非常快,时间复杂度为O(log n),在海量数据的环境中,能够快速定位目标数据。因为B+树每次查找只需要遍历树高度的次数,即使数据量很大,树的高度也很小。 能够高效地进行增删改操作B+树的平衡性能够保证树的高度非常小,大部分操作只需要遍历树的高度,而不是整颗树,…

    数据结构 2023年5月17日
    00
  • C语言二叉树的概念结构详解

    C语言二叉树的概念结构详解 什么是二叉树 二叉树是一种特殊的树形结构,它由一个根节点和若干个子树组成,其中每个节点都最多有两个子节点,分别称为它的左子节点和右子节点。 二叉树的结构 一个二叉树通常由以下几个结构组成: 数据域:存储节点所包含的数据 左节点:节点左侧的子节点,如果为空节点,则表示当前节点没有左子树 右节点:节点右侧的子节点,如果为空节点,则表示…

    数据结构 2023年5月17日
    00
  • C语言线性表顺序存储结构实例详解

    C语言线性表顺序存储结构实例详解 线性表的定义 线性表是数据结构中最基本的结构之一。它们是由相同数据类型的一组数据元素组成的序列。线性表具有唯一的首元素和唯一的末元素,除第一个元素之外的每个元素都有唯一的前继,除最后一个元素之外的每个元素都有唯一的后继。 线性表的存储方式 线性表有两种存储方式: 顺序存储和链式存储。 顺序存储采用一段连续的内存空间来存储线性…

    数据结构 2023年5月17日
    00
  • js处理层级数据结构的方法小结

    “JS处理层级数据结构的方法小结”是一篇讲解JavaScript如何处理嵌套数据结构的文章。在现代的web应用中,嵌套结构是非常常见的,比如JSON数据、树形数据等。以下是对该话题的详细讲解: 1. 嵌套数据结构的概念 指的是包含嵌套关系的数据类型,如数组、对象、树形结构、XML文档等。这些类型之间有着固定层级关系,包含多个层次的数据。嵌套数据结构的处理,往…

    数据结构 2023年5月17日
    00
  • 详解Pytorch中的tensor数据结构

    详解Pytorch中的Tensor数据结构 在Pytorch中,Tensor是一种重要的数据结构,它是一个多维数组(类似于NumPy的ndarray),并且支持GPU加速操作。在本文中,我们将详细介绍Pytorch中的Tensor数据结构,包括如何创建、初始化、检索和修改Tensor对象。 创建Tensor对象 创建Tensor对象的方法有很多种。以下是一些…

    数据结构 2023年5月17日
    00
  • Java数据结构之有向图设计与实现详解

    Java数据结构之有向图设计与实现详解 什么是有向图 有向图是一种图形结构,其中每一个节点都有一个方向,即它指向或被其他节点指向。有向图可以用来表示许多实际问题,如路线、依赖关系、状态转移等。 有向图的基本概念 在有向图中,每一个节点都有一个唯一的标识符,被称为节点ID。如果从节点A到节点B存在一条有向边,则称B是A的后继节点,A是B的前驱节点。节点的度数是…

    数据结构 2023年5月17日
    00
  • 自制PHP框架之模型与数据库

    很好,下面我将为您详细讲解如何自制PHP框架中的模型与数据库部分。 什么是模型和数据库? 在讲解自制PHP框架的模型和数据库前,我们需要先了解什么是模型和数据库。在PHP框架架构中,模型是用来操作数据库的一种机制,用来处理对数据表的增删改查等操作,并且与数据库的连接是一定的。而数据库是一种数据存储工具,用于存储数据并提供数据操作的方法,例如数据的增删改查等。…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部