数据结构小记【Python/C++版】——AVL树篇

一,基本概念

AVL树是一种结构平衡的BST树,被称为平衡二叉树。

AVL树的具体特点是,每一个节点的左子树和右子树的高度差的绝对值最多为1,且其左子树和右子树也是AVL树。

BST树有时候会退化为一个链表,但是AVL树不会,因为AVL树具有自平衡属性。

AVL的自平衡是基于平衡因子来维持,平衡因子就是BST树中每个节点的左子树和右子树的高度差。因此对于AVL树来说,平衡因子的值应始终为 -1、0 或 +1。

如果平衡因子为1,则左子树比右子树深一级。

如果平衡因子为0,则左右子树处于相同的深度。

如果平衡因子为-1,则左子树比右子树浅一级。

**最小不平衡子树:**距离插入节点最近,且以平衡因子绝对值大于1的节点为根结点的子树。

二,AVL树的基本操作

插入节点和删除节点的操作,请参考前面写过的BST树的基本操作。

此处主要讲AVL树的再平衡问题,因AVL树是否平衡是基于平衡因子来衡量的,而插入节点和删除节点的操作容易打破AVL树原有的平衡,使平衡因子的绝对值大于1。此时的AVL树变成了不平衡的BST树,为了让BST树再次平衡成为AVL树,需要进行一系列的操作来改变树的结构,这个操作被称为旋转

当整个AVL树失去平衡时,仅需要对最小不平衡子树进行旋转即可。

旋转操作的本质是子节点和根节点位置的互换

1.左旋

1.发现一个子树的平衡因子为-2,定为最小不平衡子树。

2.找到破坏平衡的节点,即最小不平衡子树的根节点。

3.左旋最小不平衡子树,使破坏平衡的节点成为子树的左子节点。

2.右旋

1.发现一个子树的平衡因子为2,定为最小不平衡子树

2.找到破坏平衡的节点,即最小不平衡子树的根节点。

3.右旋最小不平衡子树,使破坏平衡的节点成为子树的右子节点。

3.左右旋

左旋+右旋的组合

对根节点的左子树执行左旋。

对整个不平衡子树执行右旋。

4.右左旋

右旋+左旋的组合

对根节点的右子树执行右旋。

对整个不平衡子树执行左旋。

三,AVL树的代码实现

案例场景:

原始的AVL树:

插入节点"9",基于BST树的插入操作,生成新的不平衡的BST树。

此时,BST树的最小不平衡子树是:11->8->9(广度优先遍历)。

最小不平衡子树经过左右旋以后达到再平衡,生成新的AVL树。

再平衡以后的AVL树。

代码实现:

Python实现:

python 复制代码
import sys

#初始化节点
class TreeNode(object):
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None
        self.height = 1

class AVLTree(object):
    def insert_node(self, root, key):
        #基于BST树的方式插入节点
        if not root:
            return TreeNode(key)
        elif key < root.key:
            root.left = self.insert_node(root.left, key)
        else:
            root.right = self.insert_node(root.right, key)

        root.height = 1 + max(self.getHeight(root.left),
                              self.getHeight(root.right))

        #BST树再平衡
        balanceFactor = self.getBalance(root)
        if balanceFactor > 1:
            if key < root.left.key:
                return self.rightRotate(root)
            else:
                root.left = self.leftRotate(root.left)
                return self.rightRotate(root)

        if balanceFactor < -1:
            if key > root.right.key:
                return self.leftRotate(root)
            else:
                root.right = self.rightRotate(root.right)
                return self.leftRotate(root)
        return root

    def leftRotate(self, z):
        y = z.right
        T2 = y.left
        y.left = z
        z.right = T2
        z.height = 1 + max(self.getHeight(z.left),
                           self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                           self.getHeight(y.right))
        return y

    def rightRotate(self, z):
        y = z.left
        T3 = y.right
        y.right = z
        z.left = T3
        z.height = 1 + max(self.getHeight(z.left),
                           self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                           self.getHeight(y.right))
        return y

    def getHeight(self, root):
        if not root:
            return 0
        return root.height

    def getBalance(self, root):
        if not root:
            return 0
        return self.getHeight(root.left) - self.getHeight(root.right)

    def preOrder(self, root):
        if not root:
            return
        print("{0} ".format(root.key), end="")
        self.preOrder(root.left)
        self.preOrder(root.right)

    def printTree(self, currPtr, indent, last):
        if currPtr != None:
            sys.stdout.write(indent)
            if last:
                sys.stdout.write("R----")
                indent += "     "
            else:
                sys.stdout.write("L----")
                indent += "|    "
            print(currPtr.key)
            self.printTree(currPtr.left, indent, False)
            self.printTree(currPtr.right, indent, True)

myTree = AVLTree()
root = None
nums = [33, 13, 53, 11, 21, 61, 8]
for num in nums:
    root = myTree.insert_node(root, num)
myTree.printTree(root, "", True)
new_node = 9
root = myTree.insert_node(root, new_node)
print("After Insert: ")
myTree.printTree(root, "", True)

运行结果:

bash 复制代码
R----33
     L----13
     |    L----11
     |    |    L----8
     |    R----21
     R----53
          R----61
After Insert:
R----33
     L----13
     |    L----9
     |    |    L----8
     |    |    R----11
     |    R----21
     R----53
          R----61

C++实现:

cpp 复制代码
#include <iostream>
using namespace std;

//初始化节点
class Node {
public:
    int key;
    Node* left;
    Node* right;
    int height;
};
int max(int a, int b);

int height(Node* N) {
    if (N == NULL)
        return 0;
    return N->height;
}
int max(int a, int b) {
    return (a > b) ? a : b;
}

Node* newNode(int key) {
    Node* node = new Node();
    node->key = key;
    node->left = NULL;
    node->right = NULL;
    node->height = 1;
    return (node);
}

Node* rightRotate(Node* y) {
    Node* x = y->left;
    Node* T2 = x->right;
    x->right = y;
    y->left = T2;
    y->height = max(height(y->left),
        height(y->right)) +
        1;
    x->height = max(height(x->left),
        height(x->right)) +
        1;
    return x;
}

Node* leftRotate(Node* x) {
    Node* y = x->right;
    Node* T2 = y->left;
    y->left = x;
    x->right = T2;
    x->height = max(height(x->left),
        height(x->right)) +
        1;
    y->height = max(height(y->left),
        height(y->right)) +
        1;
    return y;
}

int getBalanceFactor(Node* N) {
    if (N == NULL)
        return 0;
    return height(N->left) -
        height(N->right);
}

Node* insertNode(Node* node, int key) {
    //基于BST树的方式插入节点
    if (node == NULL)
        return (newNode(key));
    if (key < node->key)
        node->left = insertNode(node->left, key);
    else if (key > node->key)
        node->right = insertNode(node->right, key);
    else
        return node;

    //BST树再平衡
    node->height = 1 + max(height(node->left),
        height(node->right));
    int balanceFactor = getBalanceFactor(node);
    if (balanceFactor > 1) {
        if (key < node->left->key) {
            return rightRotate(node);
        }
        else if (key > node->left->key) {
            node->left = leftRotate(node->left);
            return rightRotate(node);
        }
    }
    if (balanceFactor < -1) {
        if (key > node->right->key) {
            return leftRotate(node);
        }
        else if (key < node->right->key) {
            node->right = rightRotate(node->right);
            return leftRotate(node);
        }
    }
    return node;
}

void printTree(Node* root, string indent, bool last) {
    if (root != nullptr) {
        cout << indent;
        if (last) {
            cout << "R----";
            indent += "   ";
        }
        else {
            cout << "L----";
            indent += "|  ";
        }
        cout << root->key << endl;
        printTree(root->left, indent, false);
        printTree(root->right, indent, true);
    }
}
int main() {
    Node* root = NULL;
    root = insertNode(root, 33);
    root = insertNode(root, 13);
    root = insertNode(root, 53);
    root = insertNode(root, 11);
    root = insertNode(root, 21);
    root = insertNode(root, 61);
    root = insertNode(root, 8);
    printTree(root, "", true);
    root = insertNode(root, 9);
    cout << "After Insert:" << endl;
    printTree(root, "", true);
}

运行结果:

bash 复制代码
R----33
   L----13
   |  L----11
   |  |  L----8
   |  R----21
   R----53
      R----61
After Insert:
R----33
   L----13
   |  L----9
   |  |  L----8
   |  |  R----11
   |  R----21
   R----53
      R----61

四,参考阅读

https://www.guru99.com/avl-tree.html

https://www.programiz.com/dsa/avl-tree

相关推荐
平行的时光线10 分钟前
学习python的第十三天之函数——函数的返回值
python
kitesxian1 小时前
Leetcode207. 课程表(HOT100)
数据结构
咸芝麻鱼1 小时前
Django数据迁移出错,解决raise NodeNotFoundError问题
后端·python·django
明月*清风1 小时前
【数据结构专栏】二叉搜索树(Binary Search Tree)的剖析?
开发语言·数据结构·c++·visualstudio
qiaoqiaohonghu1 小时前
c/c++ 用easyx图形库写一个射击游戏
c语言·c++·游戏
Beau_Will1 小时前
数据结构-树状数组专题(2)
数据结构·c++·算法
小熙智菏——Sunspot1 小时前
Linux系统性能优化技巧
linux·运维·性能优化
雪碧聊技术1 小时前
RabbitMQ3:Java客户端快速入门
java·开发语言·rabbitmq·amqp·spring amqp·rabbittemplate
Sinsa_SI1 小时前
2024年9月中国电子学会青少年软件编程(Python)等级考试试卷(六级)答案 + 解析
开发语言·python·等级考试·电子学会·考级
济南信息学奥赛刘老师2 小时前
GESP考试大纲
开发语言·c++·算法·青少年编程