AVL树与红黑树的原理与特性

在计算机科学中,平衡二叉搜索树是一种重要的数据结构,能够有效地存储和检索数据。AVL树和红黑树是两种常见的自平衡二叉搜索树,它们各自有自己的特点和应用场景。本文将深入探讨这两种树的原理、特性以及简单的代码示例。

AVL树

AVL树是一种高度平衡的二叉搜索树,得名于其发明者G.M. Adelson-Velsky和E.M. Landis。AVL树的关键思想是保持树的高度平衡,具体来说,对于树中的任何节点,其左子树和右子树的高度差(平衡因子)不能超过1。

特性:

  1. 高度平衡:任意节点的左右子树高度差不超过1。
  2. 二叉搜索树特性:对于每个节点,左子树的值小于节点值,右子树的值大于节点值。
  3. 旋转操作:当树不再平衡时,通过旋转操作(单旋转或双旋转)来恢复平衡。

代码示例:

以下是实现AVL树的基本结构及插入操作的代码示例:

#include <iostream>
using namespace std;

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

    AVLNode(int value) : key(value), left(nullptr), right(nullptr), height(1) {}
};

class AVLTree {
public:
    AVLNode* root;

    AVLTree() : root(nullptr) {}

    int height(AVLNode* node) {
        return node ? node->height : 0;
    }

    int getBalance(AVLNode* node) {
        return node ? height(node->left) - height(node->right) : 0;
    }

    AVLNode* rightRotate(AVLNode* y) {
        AVLNode* x = y->left;
        AVLNode* 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;
    }

    AVLNode* leftRotate(AVLNode* x) {
        AVLNode* y = x->right;
        AVLNode* 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;
    }

    AVLNode* insert(AVLNode* node, int key) {
        if (!node) 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
            return node; // 重复节点不插入

        node->height = max(height(node->left), height(node->right)) + 1;

        int balance = getBalance(node);

        // 平衡调整
        if (balance > 1 && key < node->left->key)
            return rightRotate(node);
        if (balance < -1 && key > node->right->key)
            return leftRotate(node);
        if (balance > 1 && key > node->left->key) {
            node->left = leftRotate(node->left);
            return rightRotate(node);
        }
        if (balance < -1 && key < node->right->key) {
            node->right = rightRotate(node->right);
            return leftRotate(node);
        }

        return node;
    }

    void preOrder(AVLNode* node) {
        if (node) {
            cout << node->key << " ";
            preOrder(node->left);
            preOrder(node->right);
        }
    }

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

    void display() {
        preOrder(root);
        cout << endl;
    }
};

int main() {
    AVLTree tree;
    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(40);
    tree.insert(50);
    tree.insert(25);

    cout << "AVL树的前序遍历结果是: ";
    tree.display();

    return 0;
}

红黑树

红黑树是一种平衡的二叉搜索树,每个节点都有一个颜色属性(红色或黑色)。通过对节点颜色的约束,红黑树保证了树的高度大致是对数级别,从而确保了基本操作(插入、删除、查找)的时间复杂度为O(log n)。

特性:

  1. 每个节点是红色或黑色
  2. 根节点是黑色
  3. 每个叶子节点(NIL或空节点)是黑色
  4. 如果一个节点是红色,则它的两个子节点必须是黑色(即没有两个红色相邻)。
  5. 从任一节点到其每个叶子节点的路径都包含相同数量的黑色节点(称为黑色高度)。

代码示例:

以下是红黑树的插入操作的简化版代码示例:

#include <iostream>
using namespace std;

enum Color { RED, BLACK };

struct RBNode {
    int data;
    Color color;
    RBNode *left, *right, *parent;

    RBNode(int data) {
        this->data = data;
        left = right = parent = nullptr;
        color = RED; // 新节点为红色
    }
};

class RBTree {
private:
    RBNode *root;

    void rotateLeft(RBNode *&node) {
        RBNode *node_y = node->right;
        node->right = node_y->left;

        if (node_y->left != nullptr) {
            node_y->left->parent = node;
        }

        node_y->parent = node->parent;

        if (node->parent == nullptr) {
            root = node_y;
        } else if (node == node->parent->left) {
            node->parent->left = node_y;
        } else {
            node->parent->right = node_y;
        }

        node_y->left = node;
        node->parent = node_y;
    }

    void rotateRight(RBNode *&node) {
        RBNode *node_y = node->left;
        node->left = node_y->right;

        if (node_y->right != nullptr) {
            node_y->right->parent = node;
        }

        node_y->parent = node->parent;

        if (node->parent == nullptr) {
            root = node_y;
        } else if (node == node->parent->left) {
            node->parent->left = node_y;
        } else {
            node->parent->right = node_y;
        }

        node_y->right = node;
        node->parent = node_y;
    }

    void fixViolations(RBNode *&node) {
        RBNode *parent_node = nullptr;
        RBNode *grandparent_node = nullptr;

        while ((node != root) && (node->color == RED) && (node->parent->color == RED)) {
            parent_node = node->parent;
            grandparent_node = parent_node->parent;

            if (parent_node == grandparent_node->left) {
                RBNode *uncle_node = grandparent_node->right;

                if (uncle_node != nullptr && uncle_node->color == RED) {
                    grandparent_node->color = RED;
                    parent_node->color = BLACK;
                    uncle_node->color = BLACK;
                    node = grandparent_node; // 继续从祖父节点向上检查
                } else {
                    if (node == parent_node->right) {
                        rotateLeft(parent_node);
                        node = parent_node;
                        parent_node = node->parent;
                    }
                    rotateRight(grandparent_node);
                    swap(parent_node->color, grandparent_node->color);
                    node = parent_node;
                }
            } else {
                RBNode *uncle_node = grandparent_node->left;

                if ((uncle_node != nullptr) && (uncle_node->color == RED)) {
                    grandparent_node->color = RED;
                    parent_node->color = BLACK;
                    uncle_node->color = BLACK;
                    node = grandparent_node; // 继续从祖父节点向上检查
                } else {
                    if (node == parent_node->left) {
                        rotateRight(parent_node);
                        node = parent_node;
                        parent_node = node->parent;
                    }
                    rotateLeft(grandparent_node);
                    swap(parent_node->color, grandparent_node->color);
                    node = parent_node;
                }
            }
        }
        root->color = BLACK; // 根节点始终为黑色
    }

public:
    RBTree() {
        root = nullptr;
    }

    void insert(const int &data) {
        RBNode *node = new RBNode(data);
        root = BSTInsert(root, node);
        fixViolations(node);
    }

    RBNode* BSTInsert(RBNode* root, RBNode *node) {
        if (root == nullptr) return node;

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

    void InOrder() {
        InOrderHelper(root);
    }

    void InOrderHelper(RBNode* node) {
        if (node == nullptr) return;

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

int main() {
    RBTree tree;
    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(15);

    cout << "红黑树的中序遍历结果是: ";
    tree.InOrder();
    cout << endl;

    return 0;
}

总结

AVL树和红黑树都是优秀的自平衡二叉搜索树,适用于不同的场景。AVL树具有更严格的平衡条件,适合查询频繁的应用;而红黑树则具有更好的插入和删除性能,适合修改频繁的情况。理解它们的原理和特性,不仅有助于深入掌握数据结构的基础,也为实际开发中的问题提供了有效的解决方案。

点赞(0) 打赏

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部