C++ -- 红黑树的基本操作

目录

摘要

基本规则

基本操作

[利用Graphviz 库](#利用Graphviz 库)

总结


摘要

红黑树是一种自平衡的二叉搜索树,它在插入和删除节点时,通过颜色和旋转操作保持树的平衡,确保插入、删除和查找的时间复杂度都是 (O(log n))。红黑树的每个节点都有一个颜色属性,红色或黑色。通过一些规则,红黑树保持了相对平衡,使得最长路径长度不会超过最短路径长度的两倍。

基本规则

  1. 每个节点不是红色就是黑色。

  2. 根节点是黑色。

  3. 每个叶子节点(NIL 节点)是黑色。

  4. 如果一个节点是红色的,则它的两个子节点都是黑色的(从每个叶子到根的所有路径上不能有两个连续的红色节点)。

  5. 从任一节点到其每个叶子的所有简单路径都包含相同数量的黑色节点。

基本操作

插入操作

cpp 复制代码
#include <iostream>

enum Color { RED, BLACK };

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

    Node(int data) : data(data), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

class RedBlackTree {
public:
    RedBlackTree() : root(nullptr) {}

    void insert(int data) {
        Node* newNode = new Node(data);
        root = bstInsert(root, newNode);
        fixViolation(newNode);
    }

    void inorder() { inorderHelper(root); }

private:
    Node* root;

    Node* bstInsert(Node* root, Node* 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 fixViolation(Node* node) {
        Node* parent = nullptr;
        Node* grandParent = nullptr;

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

            if (parent == grandParent->left) {
                Node* uncle = grandParent->right;

                if (uncle != nullptr && uncle->color == RED) {
                    grandParent->color = RED;
                    parent->color = BLACK;
                    uncle->color = BLACK;
                    node = grandParent;
                } else {
                    if (node == parent->right) {
                        rotateLeft(parent);
                        node = parent;
                        parent = node->parent;
                    }
                    rotateRight(grandParent);
                    std::swap(parent->color, grandParent->color);
                    node = parent;
                }
            } else {
                Node* uncle = grandParent->left;

                if (uncle != nullptr && uncle->color == RED) {
                    grandParent->color = RED;
                    parent->color = BLACK;
                    uncle->color = BLACK;
                    node = grandParent;
                } else {
                    if (node == parent->left) {
                        rotateRight(parent);
                        node = parent;
                        parent = node->parent;
                    }
                    rotateLeft(grandParent);
                    std::swap(parent->color, grandParent->color);
                    node = parent;
                }
            }
        }
        root->color = BLACK;
    }

    void rotateLeft(Node* node) {
        Node* rightNode = node->right;
        node->right = rightNode->left;

        if (node->right != nullptr) node->right->parent = node;
        rightNode->parent = node->parent;

        if (node->parent == nullptr) root = rightNode;
        else if (node == node->parent->left) node->parent->left = rightNode;
        else node->parent->right = rightNode;

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

    void rotateRight(Node* node) {
        Node* leftNode = node->left;
        node->left = leftNode->right;

        if (node->left != nullptr) node->left->parent = node;
        leftNode->parent = node->parent;

        if (node->parent == nullptr) root = leftNode;
        else if (node == node->parent->left) node->parent->left = leftNode;
        else node->parent->right = leftNode;

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

    void inorderHelper(Node* root) {
        if (root == nullptr) return;
        inorderHelper(root->left);
        std::cout << root->data << " ";
        inorderHelper(root->right);
    }
};

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

    std::cout << "Inorder traversal of the constructed tree is ";
    tree.inorder();
    std::cout << std::endl;

    return 0;
}
cpp 复制代码
// Output
Inorder traversal of the constructed tree is 10 15 20 30

     20(B)
   /    \
10(B)  30(B)
   \
   15(R)

插入和删除操作

cpp 复制代码
#include <iostream>
#include <queue>

enum Color { RED, BLACK };

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

    Node(int data) : data(data), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}

    Node* sibling() {
        if (parent == nullptr) return nullptr;
        return this == parent->left ? parent->right : parent->left;
    }

    bool hasRedChild() {
        return (left != nullptr && left->color == RED) || (right != nullptr && right->color == RED);
    }
};

class RedBlackTree {
public:
    Node* root;

    RedBlackTree() : root(nullptr) {}

    void insert(int data) {
        Node* newNode = new Node(data);
        root = bstInsert(root, newNode);
        fixViolation(newNode);
    }

    void deleteNode(int data) {
        Node* nodeToDelete = search(root, data);
        if (nodeToDelete == nullptr) return;
        deleteBSTNode(nodeToDelete);
    }

    void inorder() { inorderHelper(root); }

    void levelOrder() {
        if (root == nullptr) return;
        std::queue<Node*> q;
        q.push(root);

        while (!q.empty()) {
            Node* temp = q.front();
            std::cout << temp->data << " ";
            q.pop();

            if (temp->left != nullptr)
                q.push(temp->left);

            if (temp->right != nullptr)
                q.push(temp->right);
        }
    }

private:
    Node* bstInsert(Node* root, Node* 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;
    }

    Node* search(Node* root, int data) {
        if (root == nullptr || root->data == data) return root;
        return data < root->data ? search(root->left, data) : search(root->right, data);
    }

    void deleteBSTNode(Node* node) {
        Node* replacement = BSTreplace(node);
        bool bothBlack = ((replacement == nullptr || replacement->color == BLACK) && (node->color == BLACK));
        Node* parent = node->parent;

        if (replacement == nullptr) {
            if (node == root) {
                root = nullptr;
            } else {
                if (bothBlack) {
                    fixDoubleBlack(node);
                } else {
                    if (node->sibling() != nullptr) node->sibling()->color = RED;
                }
                if (node == node->parent->left) {
                    node->parent->left = nullptr;
                } else {
                    node->parent->right = nullptr;
                }
            }
            delete node;
            return;
        }

        if (node->left == nullptr || node->right == nullptr) {
            if (node == root) {
                node->data = replacement->data;
                node->left = node->right = nullptr;
                delete replacement;
            } else {
                if (node == node->parent->left) {
                    parent->left = replacement;
                } else {
                    parent->right = replacement;
                }
                delete node;
                replacement->parent = parent;
                if (bothBlack) {
                    fixDoubleBlack(replacement);
                } else {
                    replacement->color = BLACK;
                }
            }
            return;
        }

        std::swap(node->data, replacement->data);
        deleteBSTNode(replacement);
    }

    Node* BSTreplace(Node* node) {
        if (node->left != nullptr && node->right != nullptr) return successor(node->right);
        if (node->left == nullptr && node->right == nullptr) return nullptr;
        return node->left != nullptr ? node->left : node->right;
    }

    Node* successor(Node* node) {
        Node* temp = node;
        while (temp->left != nullptr) temp = temp->left;
        return temp;
    }

    void fixViolation(Node* node) {
        Node* parent = nullptr;
        Node* grandParent = nullptr;

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

            if (parent == grandParent->left) {
                Node* uncle = grandParent->right;

                if (uncle != nullptr && uncle->color == RED) {
                    grandParent->color = RED;
                    parent->color = BLACK;
                    uncle->color = BLACK;
                    node = grandParent;
                } else {
                    if (node == parent->right) {
                        rotateLeft(parent);
                        node = parent;
                        parent = node->parent;
                    }
                    rotateRight(grandParent);
                    std::swap(parent->color, grandParent->color);
                    node = parent;
                }
            } else {
                Node* uncle = grandParent->left;

                if (uncle != nullptr && uncle->color == RED) {
                    grandParent->color = RED;
                    parent->color = BLACK;
                    uncle->color = BLACK;
                    node = grandParent;
                } else {
                    if (node == parent->left) {
                        rotateRight(parent);
                        node = parent;
                        parent = node->parent;
                    }
                    rotateLeft(grandParent);
                    std::swap(parent->color, grandParent->color);
                    node = parent;
                }
            }
        }
        root->color = BLACK;
    }

    void fixDoubleBlack(Node* node) {
        if (node == root) return;

        Node* sibling = node->sibling();
        Node* parent = node->parent;
        if (sibling == nullptr) {
            fixDoubleBlack(parent);
        } else {
            if (sibling->color == RED) {
                parent->color = RED;
                sibling->color = BLACK;
                if (sibling == parent->left) {
                    rotateRight(parent);
                } else {
                    rotateLeft(parent);
                }
                fixDoubleBlack(node);
            } else {
                if (sibling->hasRedChild()) {
                    if (sibling->left != nullptr && sibling->left->color == RED) {
                        if (sibling == parent->left) {
                            sibling->left->color = sibling->color;
                            sibling->color = parent->color;
                            rotateRight(parent);
                        } else {
                            sibling->left->color = parent->color;
                            rotateRight(sibling);
                            rotateLeft(parent);
                        }
                    } else {
                        if (sibling == parent->left) {
                            sibling->right->color = parent->color;
                            rotateLeft(sibling);
                            rotateRight(parent);
                        } else {
                            sibling->right->color = sibling->color;
                            sibling->color = parent->color;
                            rotateLeft(parent);
                        }
                    }
                    parent->color = BLACK;
                } else {
                    sibling->color = RED;
                    if (parent->color == BLACK) {
                        fixDoubleBlack(parent);
                    } else {
                        parent->color = BLACK;
                    }
                }
            }
        }
    }

    void rotateLeft(Node* node) {
        Node* rightNode = node->right;
        node->right = rightNode->left;

        if (node->right != nullptr) node->right->parent = node;
        rightNode->parent = node->parent;

        if (node->parent == nullptr) root = rightNode;
        else if (node == node->parent->left) node->parent->left = rightNode;
        else node->parent->right = rightNode;

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

    void rotateRight(Node* node) {
        Node* leftNode = node->left;
        node->left = leftNode->right;

        if (node->left != nullptr) node->left->parent = node;
        leftNode->parent = node->parent;

        if (node->parent == nullptr) root = leftNode;
        else if (node == node->parent->left) node->parent->left = leftNode;
        else node->parent->right = leftNode;

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

    void inorderHelper(Node* root) {
        if (root == nullptr) return;
        inorderHelper(root->left);
        std::cout << root->data << " ";
        inorderHelper(root->right);
    }
};

int main() {
    RedBlackTree tree;
    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(15);
    tree.insert(25);
    tree.insert(5);

    std::cout << "Inorder traversal of the constructed tree is ";
    tree.inorder();
    std::cout << std::endl;

    tree.deleteNode(20);

    std::cout << "Inorder traversal after deleting 20 is ";
    tree.inorder();
    std::cout << std::endl;

    std::cout << "Level order traversal of the tree is ";
    tree.levelOrder();
    std::cout << std::endl;

    return 0;
}
cpp 复制代码
// Output

Inorder traversal of the constructed tree is 5 10 15 20 25 30 
Inorder traversal after deleting 20 is 5 10 15 25 30 
Level order traversal of the tree is 15 10 30 5 25 


     15(B)
   /    \
10(B)  30(B)
 /     /
5(B)  25(R)

利用Graphviz 库

利用 Graphviz 库的图形化表示我们需要生成的红黑树。

Graphviz Online

cpp 复制代码
#include <iostream>
#include <fstream>
#include <queue>

enum Color { RED, BLACK };

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

    Node(int data) : data(data), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}

    Node* sibling() {
        if (parent == nullptr) return nullptr;
        return this == parent->left ? parent->right : parent->left;
    }

    bool hasRedChild() {
        return (left != nullptr && left->color == RED) || (right != nullptr && right->color == RED);
    }
};

class RedBlackTree {
public:
    Node* root;

    RedBlackTree() : root(nullptr) {}

    void insert(int data) {
        Node* newNode = new Node(data);
        root = bstInsert(root, newNode);
        fixViolation(newNode);
    }

    void deleteNode(int data) {
        Node* nodeToDelete = search(root, data);
        if (nodeToDelete == nullptr) return;
        deleteBSTNode(nodeToDelete);
    }

    void inorder() { inorderHelper(root); }

    void levelOrder() {
        if (root == nullptr) return;
        std::queue<Node*> q;
        q.push(root);

        while (!q.empty()) {
            Node* temp = q.front();
            std::cout << temp->data << " ";
            q.pop();

            if (temp->left != nullptr)
                q.push(temp->left);

            if (temp->right != nullptr)
                q.push(temp->right);
        }
    }

    void generateGraphviz(const std::string& filename) {
        std::ofstream file(filename);
        file << "digraph G {\n";
        if (root == nullptr) {
            file << "}\n";
            return;
        }
        generateGraphvizHelper(file, root);
        file << "}\n";
    }

private:
    Node* bstInsert(Node* root, Node* 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;
    }

    Node* search(Node* root, int data) {
        if (root == nullptr || root->data == data) return root;
        return data < root->data ? search(root->left, data) : search(root->right, data);
    }

    void deleteBSTNode(Node* node) {
        Node* replacement = BSTreplace(node);
        bool bothBlack = ((replacement == nullptr || replacement->color == BLACK) && (node->color == BLACK));
        Node* parent = node->parent;

        if (replacement == nullptr) {
            if (node == root) {
                root = nullptr;
            } else {
                if (bothBlack) {
                    fixDoubleBlack(node);
                } else {
                    if (node->sibling() != nullptr) node->sibling()->color = RED;
                }
                if (node == node->parent->left) {
                    node->parent->left = nullptr;
                } else {
                    node->parent->right = nullptr;
                }
            }
            delete node;
            return;
        }

        if (node->left == nullptr || node->right == nullptr) {
            if (node == root) {
                node->data = replacement->data;
                node->left = node->right = nullptr;
                delete replacement;
            } else {
                if (node == node->parent->left) {
                    parent->left = replacement;
                } else {
                    parent->right = replacement;
                }
                delete node;
                replacement->parent = parent;
                if (bothBlack) {
                    fixDoubleBlack(replacement);
                } else {
                    replacement->color = BLACK;
                }
            }
            return;
        }

        std::swap(node->data, replacement->data);
        deleteBSTNode(replacement);
    }

    Node* BSTreplace(Node* node) {
        if (node->left != nullptr && node->right != nullptr) return successor(node->right);
        if (node->left == nullptr && node->right == nullptr) return nullptr;
        return node->left != nullptr ? node->left : node->right;
    }

    Node* successor(Node* node) {
        Node* temp = node;
        while (temp->left != nullptr) temp = temp->left;
        return temp;
    }

    void fixViolation(Node* node) {
        Node* parent = nullptr;
        Node* grandParent = nullptr;

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

            if (parent == grandParent->left) {
                Node* uncle = grandParent->right;

                if (uncle != nullptr && uncle->color == RED) {
                    grandParent->color = RED;
                    parent->color = BLACK;
                    uncle->color = BLACK;
                    node = grandParent;
                } else {
                    if (node == parent->right) {
                        rotateLeft(parent);
                        node = parent;
                        parent = node->parent;
                    }
                    rotateRight(grandParent);
                    std::swap(parent->color, grandParent->color);
                    node = parent;
                }
            } else {
                Node* uncle = grandParent->left;

                if (uncle != nullptr && uncle->color == RED) {
                    grandParent->color = RED;
                    parent->color = BLACK;
                    uncle->color = BLACK;
                    node = grandParent;
                } else {
                    if (node == parent->left) {
                        rotateRight(parent);
                        node = parent;
                        parent = node->parent;
                    }
                    rotateLeft(grandParent);
                    std::swap(parent->color, grandParent->color);
                    node = parent;
                }
            }
        }
        root->color = BLACK;
    }

    void fixDoubleBlack(Node* node) {
        if (node == root) return;

        Node* sibling = node->sibling();
        Node* parent = node->parent;
        if (sibling == nullptr) {
            fixDoubleBlack(parent);
        } else {
            if (sibling->color == RED) {
                parent->color = RED;
                sibling->color = BLACK;
                if (sibling == parent->left) {
                    rotateRight(parent);
                } else {
                    rotateLeft(parent);
                }
                fixDoubleBlack(node);
            } else {
                if (sibling->hasRedChild()) {
                    if (sibling->left != nullptr && sibling->left->color == RED) {
                        if (sibling == parent->left) {
                            sibling->left->color = sibling->color;
                            sibling->color = parent->color;
                            rotateRight(parent);
                        } else {
                            sibling->left->color = parent->color;
                            rotateRight(sibling);
                            rotateLeft(parent);
                        }
                    } else {
                        if (sibling == parent->left) {
                            sibling->right->color = parent->color;
                            rotateLeft(sibling);
                            rotateRight(parent);
                        } else {
                            sibling->right->color = sibling->color;
                            sibling->color = parent->color;
                            rotateLeft(parent);
                        }
                    }
                    parent->color = BLACK;
                } else {
                    sibling->color = RED;
                    if (parent->color == BLACK) {
                        fixDoubleBlack(parent);
                    } else {
                        parent->color = BLACK;
                    }
                }
            }
        }
    }

    void rotateLeft(Node* node) {
        Node* rightNode = node->right;
        node->right = rightNode->left;

        if (node->right != nullptr) node->right->parent = node;
        rightNode->parent = node->parent;

        if (node->parent == nullptr) root = rightNode;
        else if (node == node->parent->left) node->parent->left = rightNode;
        else node->parent->right = rightNode;

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

    void rotateRight(Node* node) {
        Node* leftNode = node->left;
        node->left = leftNode->right;

        if (node->left != nullptr) node->left->parent = node;
        leftNode->parent = node->parent;

        if (node->parent == nullptr) root = leftNode;
        else if (node == node->parent->left) node->parent->left = leftNode;
        else node->parent->right = leftNode;

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

    void inorderHelper(Node* root) {
        if (root == nullptr) return;
        inorderHelper(root->left);
        std::cout << root->data << " ";
        inorderHelper(root->right);
    }

    void generateGraphvizHelper(std::ofstream& file, Node* root) {
        if (root->left != nullptr) {
            file << root->data << " -> " << root->left->data << ";\n";
            generateGraphvizHelper(file, root->left);
        } else {
            file << "null" << root->data << "L [shape=point];\n";
            file << root->data << " -> null" << root->data << "L;\n";
        }

        if (root->right != nullptr) {
            file << root->data << " -> " << root->right->data << ";\n";
            generateGraphvizHelper(file, root->right);
        } else {
            file << "null" << root->data << "R [shape=point];\n";
            file << root->data << " -> null" << root->data << "R;\n";
        }
    }
};

int main() {
    RedBlackTree tree;
    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(15);
    tree.insert(25);
    tree.insert(5);

    tree.generateGraphviz("rbtree.dot");

    std::cout << "Graphviz dot file generated as rbtree.dot" << std::endl;

    return 0;
}
cpp 复制代码
// Output
digraph G {
10 -> 5;
10 -> 20;
20 -> 15;
20 -> 30;
30 -> 25;
null5L [shape=point];
5 -> null5L;
null5R [shape=point];
5 -> null5R;
null15L [shape=point];
15 -> null15L;
null15R [shape=point];
15 -> null15R;
null25L [shape=point];
25 -> null25L;
null25R [shape=point];
25 -> null25R;
null30L [shape=point];
30 -> null30L;
null30R [shape=point];
30 -> null30R;
}

  10
 /  \
5    20
    /  \
   15  30
       /
      25

总结

红黑树(Red-Black Tree)是一种自平衡二叉搜索树,常用于需要高效插入、删除和查找操作的数据结构中。红黑树的特点包括每个节点是红色或黑色、根节点是黑色、红色节点的子节点必须是黑色、从任一节点到其每个叶子节点的路径上的黑色节点数目相同。

相关推荐
雨中rain几秒前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
就爱学编程2 分钟前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
学术头条7 分钟前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学
Schwertlilien40 分钟前
图像处理-Ch4-频率域处理
算法
IT猿手1 小时前
最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解TP1-TP10及工程应用---盘式制动器设计,提供完整MATLAB代码
开发语言·深度学习·算法·机器学习·matlab·多目标算法
__lost1 小时前
MATLAB直接推导函数的导函数和积分形式(具体方法和用例)
数学·算法·matlab·微积分·高等数学
thesky1234561 小时前
活着就好20241224
学习·算法
ALISHENGYA1 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法
guogaocai1231 小时前
连续自成核退火热分级(SSA)技术表征共聚聚丙烯(PP)分子链结构
算法
arong_xu1 小时前
现代C++锁介绍
c++·多线程·mutex