返回

程序员必备:C++ 实现 AVL 树,轻松搞定数据结构

后端

AVL 树:自动平衡二叉搜索树指南

目录

  • 什么是 AVL 树?
  • AVL 树的性质
  • AVL 树的实现
  • C++ 代码示例
  • 常见问题解答

什么是 AVL 树?

AVL 树是一种自平衡二叉搜索树,由 Adelson-Velskii 和 Landis 在 1962 年提出。它能够自动调整自身,以保持左右子树的高度差在 1 以内。这种性质使得 AVL 树非常适合用于数据结构和算法中,因为它可以保证查找、插入和删除操作的时间复杂度为 O(log n)。

AVL 树的性质

AVL 树具有以下性质:

  • 它是一棵二叉搜索树。
  • 对于每个节点,其左右子树的高度差至多为 1。
  • 对于每个节点,其子树的高度是平衡的,即左子树的高度和右子树的高度相差不超过 1。

AVL 树的实现

AVL 树可以通过以下步骤来实现:

  1. 在插入或删除节点时,如果导致左右子树的高度差超过 1,则进行旋转操作,以恢复平衡。
  2. 旋转操作有四种类型:左旋、右旋、双左旋和双右旋。
  3. 旋转操作的时间复杂度为 O(1)。

C++ 代码示例

#include <iostream>

using namespace std;

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

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

class AVLTree {
public:
    AVLNode *root;

    AVLTree() {
        this->root = nullptr;
    }

    void insert(int data) {
        this->root = insert(this->root, data);
    }

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

        if (data < node->data) {
            node->left = insert(node->left, data);
        } else if (data > node->data) {
            node->right = insert(node->right, data);
        } else {
            return node;
        }

        updateHeight(node);

        int balanceFactor = getBalanceFactor(node);

        if (balanceFactor > 1) {
            if (data < node->left->data) {
                return rightRotate(node);
            } else {
                return leftRightRotate(node);
            }
        } else if (balanceFactor < -1) {
            if (data > node->right->data) {
                return leftRotate(node);
            } else {
                return rightLeftRotate(node);
            }
        }

        return node;
    }

    void delete(int data) {
        this->root = delete(this->root, data);
    }

    AVLNode *delete(AVLNode *node, int data) {
        if (node == nullptr) {
            return nullptr;
        }

        if (data < node->data) {
            node->left = delete(node->left, data);
        } else if (data > node->data) {
            node->right = delete(node->right, data);
        } else {
            if (node->left == nullptr) {
                AVLNode *temp = node->right;
                delete node;
                return temp;
            } else if (node->right == nullptr) {
                AVLNode *temp = node->left;
                delete node;
                return temp;
            } else {
                AVLNode *temp = findMin(node->right);
                node->data = temp->data;
                node->right = delete(node->right, temp->data);
            }
        }

        updateHeight(node);

        int balanceFactor = getBalanceFactor(node);

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

        return node;
    }

    bool search(int data) {
        return search(this->root, data);
    }

    bool search(AVLNode *node, int data) {
        if (node == nullptr) {
            return false;
        }

        if (data < node->data) {
            return search(node->left, data);
        } else if (data > node->data) {
            return search(node->right, data);
        } else {
            return true;
        }
    }

    int findMin() {
        return findMin(this->root);
    }

    int findMin(AVLNode *node) {
        if (node->left == nullptr) {
            return node->data;
        } else {
            return findMin(node->left);
        }
    }

    int findMax() {
        return findMax(this->root);
    }

    int findMax(AVLNode *node) {
        if (node->right == nullptr) {
            return node->data;
        } else {
            return findMax(node->right);
        }
    }

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

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

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

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

        updateHeight(node);
        updateHeight(leftChild);

        return leftChild;
    }

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

        updateHeight(node);
        updateHeight(rightChild);

        return rightChild;
    }

    AVLNode *leftRightRotate(AVLNode *node) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }

    AVLNode *rightLeftRotate(AVLNode *node) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }

    void printPreOrder() {
        printPreOrder(this->root);
    }

    void printPreOrder(AVLNode *node) {
        if (node == nullptr) {
            return;
        }

        cout << node->data << " ";
        printPreOrder(node->left);
        printPreOrder(node->right);
    }
};

int main() {
    AVLTree tree;

    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(40);
    tree.insert(50);

    tree.printPreOrder();

    cout << endl;

    tree.delete(20);

    tree.printPreOrder();

    cout << endl;

    cout << tree.search(30) << endl;

    cout << tree.findMin() << endl;

    cout << tree.findMax() << endl;

    return 0;
}

常见问题解答

1. AVL 树与其他平衡二叉搜索树有什么区别?

AVL 树与红黑树和替罪羊树等其他平衡二叉搜索树类似,但它们在旋转操作和平衡要求方面有所不同。AVL 树要求左右子树的高度差至多为 1,而红黑树和替罪羊树允许更大的高度差。

2. AVL 树的插入和删除操作的时间复杂度是多少?

AVL 树的插入和删除操作的时间复杂度为 O(log n),其中 n 是树中的节点数。这是因为平衡操作在 O(1) 时间内执行。

3. AVL 树在哪些应用中特别有用?

AVL