返回

红黑树:二叉搜索树、AVL树的混合体,结构详解与应用

后端

红黑树简介

红黑树是一种自平衡二叉搜索树,它兼具了二分搜索树和AVL树的优点。红黑树中的每个节点要么是红色的,要么是黑色的。红黑树的性质包括:

  • 根节点始终是黑色的。
  • 每个叶节点(NIL节点)都是黑色的。
  • 红色节点的子节点只能是黑色的。
  • 从根节点到任何叶节点的路径上,黑色节点的数量是相同的。

这些性质确保了红黑树在插入、删除和查找操作中的效率。

红黑树的插入

当向红黑树中插入一个新的节点时,首先将其标记为红色。然后,根据红黑树的性质,对树进行调整,直到满足红黑树的性质。插入操作的具体步骤如下:

  1. 将新节点插入到树中,使其成为叶节点。
  2. 如果新节点的父节点是红色的,则将新节点和其父节点的颜色交换。
  3. 如果新节点的叔节点也是红色的,则将新节点的父节点和叔节点的颜色交换,并将新节点的祖父节点的颜色标记为红色。
  4. 重复步骤2和步骤3,直到满足红黑树的性质。

红黑树的删除

当从红黑树中删除一个节点时,首先将其标记为黑色。然后,根据红黑树的性质,对树进行调整,直到满足红黑树的性质。删除操作的具体步骤如下:

  1. 将要删除的节点标记为黑色。
  2. 如果要删除的节点的子节点都是黑色的,则将其删除。
  3. 如果要删除的节点的子节点之一是红色的,则将其与红色的子节点交换颜色,并删除红色的子节点。
  4. 如果要删除的节点的子节点都是黑色的,并且要删除的节点的父节点是红色的,则将要删除的节点的父节点的颜色标记为黑色。
  5. 重复步骤2、步骤3和步骤4,直到满足红黑树的性质。

红黑树的查找

在红黑树中查找一个节点的步骤与在二分搜索树中查找一个节点的步骤相同。首先,从根节点开始,将要查找的与当前节点的关键字比较。如果关键字小于当前节点的关键字,则转到当前节点的左子树;如果关键字大于当前节点的关键字,则转到当前节点的右子树;如果关键字等于当前节点的关键字,则查找成功。

红黑树的应用

红黑树在实际应用中非常广泛,比如:

  • 路由表维护:在计算机网络中,路由表用于存储网络中各节点之间的路径信息。红黑树可以用来维护路由表,以便快速查找最优路径。
  • 文件系统索引:在文件系统中,索引用于快速查找文件。红黑树可以用来维护索引,以便快速查找指定的文件。
  • 内存管理:在内存管理中,红黑树可以用来维护内存页表。内存页表用于将虚拟内存地址转换为物理内存地址。红黑树可以快速查找内存页表中的条目,以便快速访问内存。

红黑树的代码实现

红黑树的代码实现并不复杂。以下是一个用C++实现的红黑树类:

#include <iostream>

using namespace std;

struct Node {
    int key;
    bool color;
    Node *left;
    Node *right;
    Node *parent;

    Node(int key) {
        this->key = key;
        this->color = true;
        this->left = nullptr;
        this->right = nullptr;
        this->parent = nullptr;
    }
};

class RedBlackTree {
public:
    Node *root;

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

    void insert(int key) {
        Node *new_node = new Node(key);
        insert(new_node);
    }

    void insert(Node *new_node) {
        Node *y = nullptr;
        Node *x = this->root;

        while (x != nullptr) {
            y = x;
            if (new_node->key < x->key) {
                x = x->left;
            } else {
                x = x->right;
            }
        }

        new_node->parent = y;
        if (y == nullptr) {
            this->root = new_node;
        } else if (new_node->key < y->key) {
            y->left = new_node;
        } else {
            y->right = new_node;
        }

        insert_fixup(new_node);
    }

    void insert_fixup(Node *new_node) {
        while (new_node != this->root && new_node->parent->color == true) {
            if (new_node->parent == new_node->parent->parent->left) {
                Node *uncle = new_node->parent->parent->right;

                if (uncle->color == true) {
                    new_node->parent->color = false;
                    uncle->color = false;
                    new_node->parent->parent->color = true;
                    new_node = new_node->parent->parent;
                } else {
                    if (new_node == new_node->parent->right) {
                        new_node = new_node->parent;
                        left_rotate(new_node);
                    }

                    new_node->parent->color = false;
                    new_node->parent->parent->color = true;
                    right_rotate(new_node->parent->parent);
                }
            } else {
                Node *uncle = new_node->parent->parent->left;

                if (uncle->color == true) {
                    new_node->parent->color = false;
                    uncle->color = false;
                    new_node->parent->parent->color = true;
                    new_node = new_node->parent->parent;
                } else {
                    if (new_node == new_node->parent->left) {
                        new_node = new_node->parent;
                        right_rotate(new_node);
                    }

                    new_node->parent->color = false;
                    new_node->parent->parent->color = true;
                    left_rotate(new_node->parent->parent);
                }
            }
        }

        this->root->color = false;
    }

    void left_rotate(Node *x) {
        Node *y = x->right;

        x->right = y->left;
        if (y->left != nullptr) {
            y->left->parent = x;
        }

        y->parent = x->parent;
        if (x->parent == nullptr) {
            this->root = y;
        } else if (x == x->parent->left) {
            x->parent->left = y;
        } else {
            x->parent->right = y;
        }

        y->left = x;
        x->parent = y;
    }

    void right_rotate(Node *x) {
        Node *y = x->left;

        x->left = y->right;
        if (y->right != nullptr) {
            y->right->parent = x;
        }

        y->parent = x->parent;
        if (x->parent == nullptr) {
            this->root = y;
        } else if (x == x->parent->right) {
            x->parent->right = y;
        } else {
            x->parent->left = y;
        }

        y->right = x;
        x->parent = y;
    }

    Node *search(int key) {
        Node *x = this->root;

        while (x != nullptr) {
            if (key == x->key) {
                return x;
            } else if (key < x->key) {
                x = x->left;
            } else {
                x = x->right;
            }
        }

        return nullptr;
    }

    void remove(int key) {
        Node *to_delete = search(key);

        if (to_delete == nullptr) {
            return;
        }

        Node *y = to_delete;
        bool y_original