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

相关推荐
顶呱呱程序5 分钟前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
爱吃生蚝的于勒27 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~30 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
王哈哈^_^1 小时前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
星沁城1 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
脉牛杂德1 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz1 小时前
STL--哈希
c++·算法·哈希算法
CSUC1 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++
Vanranrr1 小时前
C++ QT
java·c++·qt
kingmax542120081 小时前
初三数学,最优解问题
算法