返回

AVL树:平衡二叉搜索树的秘密武器

前端

AVL树:一种自平衡的二叉搜索树

AVL树简介

AVL树,得名于它的发明者Adelson-Velsky和Landis,是一种自平衡二叉搜索树。与普通二叉搜索树不同,AVL树通过保持左右子树的高度平衡来优化搜索、插入和删除操作,从而确保它们的时间复杂度为O(log n)。

AVL树结构

每个AVL树节点包含三个值:

  • 键: 用于标识节点的值
  • 左子树: 节点所有左子节点的集合
  • 右子树: 节点所有右子节点的集合

AVL树平衡性

AVL树通过左右子树高度平衡来保证其效率。如果左右子树高度差超过1,树将进行旋转操作以恢复平衡。

AVL树旋转

旋转操作有四种类型,用于平衡AVL树:

  • 左左旋转: 当左子树高度大于右子树高度时
  • 右右旋转: 当右子树高度大于左子树高度时
  • 左右旋转: 当左子树高度大于右子树高度,且左子节点右子树高度大于左子树高度时
  • 右左旋转: 当右子树高度大于左子树高度,且右子节点左子树高度大于右子树高度时

AVL树插入

插入操作遵循以下步骤:

  1. 将新节点插入树中
  2. 从新节点向上回溯,检查左右子树高度差是否超过1
  3. 如果高度差超过1,执行旋转操作来平衡树

代码示例(C++)

class AVLNode {
public:
    int key;
    AVLNode *left;
    AVLNode *right;
    int height;

    AVLNode(int key) {
        this->key = key;
        left = right = nullptr;
        height = 1;
    }
};

class AVLTree {
public:
    AVLNode *root;

    AVLTree() {
        root = nullptr;
    }

    void insert(int key) {
        root = insert(root, key);
    }

private:
    AVLNode *insert(AVLNode *node, int key) {
        if (node == nullptr) {
            return new AVLNode(key);
        }

        if (key < node->key) {
            node->left = insert(node->left, key);
        } else if (key > node->key) {
            node->right = insert(node->right, key);
        } else {
            // Key already exists in the tree
        }

        updateHeight(node);
        return balance(node);
    }

    AVLNode *balance(AVLNode *node) {
        int balanceFactor = getBalanceFactor(node);

        if (balanceFactor > 1) {
            if (getBalanceFactor(node->left) < 0) {
                node->left = leftRotate(node->left);
            }
            return rightRotate(node);
        } else if (balanceFactor < -1) {
            if (getBalanceFactor(node->right) > 0) {
                node->right = rightRotate(node->right);
            }
            return leftRotate(node);
        }

        return node;
    }

    AVLNode *leftRotate(AVLNode *node) {
        AVLNode *newRoot = node->right;
        node->right = newRoot->left;
        newRoot->left = node;

        updateHeight(node);
        updateHeight(newRoot);
        return newRoot;
    }

    AVLNode *rightRotate(AVLNode *node) {
        AVLNode *newRoot = node->left;
        node->left = newRoot->right;
        newRoot->right = node;

        updateHeight(node);
        updateHeight(newRoot);
        return newRoot;
    }

    void updateHeight(AVLNode *node) {
        node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
    }

    int getHeight(AVLNode *node) {
        if (node == nullptr) {
            return 0;
        }
        return node->height;
    }

    int getBalanceFactor(AVLNode *node) {
        if (node == nullptr) {
            return 0;
        }
        return getHeight(node->left) - getHeight(node->right);
    }
};

AVL树删除

删除操作遵循以下步骤:

  1. 找到要删除的节点
  2. 从树中删除节点
  3. 从被删除节点的父节点向上回溯,检查左右子树高度差是否超过1
  4. 如果高度差超过1,执行旋转操作来平衡树

AVL树复杂度

AVL树的搜索、插入和删除操作的时间复杂度均为O(log n)。

AVL树应用

AVL树广泛应用于:

  • 数据库
  • 文件系统
  • 内存管理

常见问题解答

1. AVL树和普通二叉搜索树有什么区别?

AVL树通过平衡左右子树高度来优化搜索、插入和删除操作,从而保证O(log n)的时间复杂度,而普通二叉搜索树没有这种平衡性。

2. AVL树是如何保持平衡的?

通过旋转操作,当左右子树高度差超过1时,AVL树会执行旋转操作以恢复平衡。

3. AVL树的插入和删除操作是如何工作的?

插入操作将新节点插入树中,然后检查平衡性并执行旋转操作;删除操作将节点从树中删除,然后检查平衡性并执行旋转操作。

4. AVL树的优点是什么?

  • O(log n)的时间复杂度
  • 易于插入、删除和搜索

5. AVL树的局限性是什么?

  • 维护平衡的开销
  • 比普通二叉搜索树更复杂