平衡二叉搜索树之红黑树的模拟实现(C++)

举报
William 发表于 2025/03/13 09:16:11 2025/03/13
【摘要】 平衡二叉搜索树之红黑树的模拟实现(C++) 引言红黑树是一种自平衡的二叉搜索树,广泛应用于计算机科学中以确保在最坏情况下仍能高效地进行插入、删除和查找操作。其关键特性是在不影响操作效率的前提下保持树的近似平衡。 技术背景红黑树是由 Rudolf Bayer 于1972年首次引入的,并由 Leo J. Guibas 和 Robert Sedgewick 在1978年推广。它通过颜色标记和旋转...

平衡二叉搜索树之红黑树的模拟实现(C++)

引言

红黑树是一种自平衡的二叉搜索树,广泛应用于计算机科学中以确保在最坏情况下仍能高效地进行插入、删除和查找操作。其关键特性是在不影响操作效率的前提下保持树的近似平衡。

技术背景

红黑树是由 Rudolf Bayer 于1972年首次引入的,并由 Leo J. Guibas 和 Robert Sedgewick 在1978年推广。它通过颜色标记和旋转操作来维持树的平衡,每个节点都是红色或黑色,通过几条规则确保树的高度差异最小化。

应用使用场景

  • 符号表:用于关联数组和映射,如 STL 的 mapset
  • 内存管理:在一些操作系统和垃圾回收器中用于跟踪空闲内存块。
  • 数据库:用作索引机制,支持快速数据查询。
  • 网络路由:在路由查找算法中,帮助快速定位。

原理解释

红黑树性质

  1. 节点颜色:每个节点或是红色,或是黑色。
  2. 根节点:根节点是黑色。
  3. 叶子节点:所有叶子节点(NIL 节点)均为黑色。
  4. 红色节点约束:红色节点的两个子节点必须是黑色。
  5. 路径黑色节点数:从任一节点到其每个叶子节点的所有路径都包含相同数量的黑色节点。

核心特性

  • 自平衡:通过旋转和重着色操作,保持树的平衡。
  • 时间复杂度:插入、删除和查找操作在最坏情况下为 O(log n)。

算法原理流程图

+---------------------------+
|   插入节点                |
+-------------+-------------+
              |
              v
+-------------+-------------+
|  插入并着色为红色         |
+-------------+-------------+
              |
              v
+-------------+-------------+
| 检查违反的性质            |
+-------------+-------------+
      | 违反               | 不违反
      v                  |
+-------------+          +-------------+
| 执行旋转和重新着色     |  完成
+-------------+          +-------------+

环境准备

需要安装一个支持 C++11 的编译器,例如 GCC 或 Clang。

实际详细应用代码示例实现

#include <iostream>
using namespace std;

enum Color { RED, BLACK };

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

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

class RedBlackTree {
private:
    Node *root;

protected:
    void rotateLeft(Node *&, Node *&);
    void rotateRight(Node *&, Node *&);
    void fixViolation(Node *&, Node *&);

public:
    RedBlackTree() { root = nullptr; }
    void insert(const int &n);
    void inorder();
    void levelOrder();
};

// A recursive function to insert a new node with given key in BST
Node* BSTInsert(Node* root, Node *pt) {
    if (root == nullptr)
       return pt;

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

    return root;
}

void RedBlackTree::rotateLeft(Node *&root, Node *&pt) {
    Node *pt_right = pt->right;

    pt->right = pt_right->left;

    if (pt->right != nullptr)
        pt->right->parent = pt;

    pt_right->parent = pt->parent;

    if (pt->parent == nullptr)
        root = pt_right;

    else if (pt == pt->parent->left)
        pt->parent->left = pt_right;

    else
        pt->parent->right = pt_right;

    pt_right->left = pt;
    pt->parent = pt_right;
}

void RedBlackTree::rotateRight(Node *&root, Node *&pt) {
    Node *pt_left = pt->left;

    pt->left = pt_left->right;

    if (pt->left != nullptr)
        pt->left->parent = pt;

    pt_left->parent = pt->parent;

    if (pt->parent == nullptr)
        root = pt_left;

    else if (pt == pt->parent->left)
        pt->parent->left = pt_left;

    else
        pt->parent->right = pt_left;

    pt_left->right = pt;
    pt->parent = pt_left;
}

void RedBlackTree::fixViolation(Node *&root, Node *&pt) {
    Node *parent_pt = nullptr;
    Node *grand_parent_pt = nullptr;

    while ((pt != root) && (pt->color != BLACK) &&
           (pt->parent->color == RED)) {

        parent_pt = pt->parent;
        grand_parent_pt = pt->parent->parent;

        if (parent_pt == grand_parent_pt->left) {
            Node *uncle_pt = grand_parent_pt->right;

            if (uncle_pt != nullptr && uncle_pt->color == RED) {
                grand_parent_pt->color = RED;
                parent_pt->color = BLACK;
                uncle_pt->color = BLACK;
                pt = grand_parent_pt;
            }
            else {
                if (pt == parent_pt->right) {
                    rotateLeft(root, parent_pt);
                    pt = parent_pt;
                    parent_pt = pt->parent;
                }

                rotateRight(root, grand_parent_pt);
                swap(parent_pt->color, grand_parent_pt->color);
                pt = parent_pt;
            }
        }
        else {
            Node *uncle_pt = grand_parent_pt->left;

            if ((uncle_pt != nullptr) && (uncle_pt->color == RED)) {
                grand_parent_pt->color = RED;
                parent_pt->color = BLACK;
                uncle_pt->color = BLACK;
                pt = grand_parent_pt;
            }
            else {
                if (pt == parent_pt->left) {
                    rotateRight(root, parent_pt);
                    pt = parent_pt;
                    parent_pt = pt->parent;
                }

                rotateLeft(root, grand_parent_pt);
                swap(parent_pt->color, grand_parent_pt->color);
                pt = parent_pt;
            }
        }
    }

    root->color = BLACK;
}

void RedBlackTree::insert(const int &data) {
    Node *pt = new Node(data);

    root = BSTInsert(root, pt);

    fixViolation(root, pt);
}

// Function to do inorder traversal
void inorderHelper(Node *root) {
    if (root == nullptr)
        return;

    inorderHelper(root->left);
    cout << root->data << "  ";
    inorderHelper(root->right);
}

void RedBlackTree::inorder() { inorderHelper(root); }

// Function to do level order traversal
void levelOrderHelper(Node *root) {
    if (root == nullptr)
        return;

    std::queue<Node *> q;
    q.push(root);

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

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

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

void RedBlackTree::levelOrder() { levelOrderHelper(root); }

// Driver Code
int main() {
    RedBlackTree tree;

    tree.insert(7);
    tree.insert(3);
    tree.insert(18);
    tree.insert(10);
    tree.insert(22);
    tree.insert(8);
    tree.insert(11);
    tree.insert(26);
    tree.insert(2);
    tree.insert(6);
    tree.insert(13);

    cout << "Inorder Traversal of Created Tree\n";
    tree.inorder();

    cout << "\n\nLevel Order Traversal of Created Tree\n";
    tree.levelOrder();

    return 0;
}

运行结果

执行上述程序会打印出红黑树的中序遍历和层次遍历结果,验证红黑树结构的正确性。

测试步骤以及详细代码、部署场景

  1. 编写代码

    将上述代码复制到一个 .cpp 文件中,例如 red_black_tree.cpp

  2. 编译代码

    使用 g++ 编译器:

    g++ -std=c++11 red_black_tree.cpp -o red_black_tree
    
  3. 运行程序

    执行生成的可执行文件:

    ./red_black_tree
    

    检查输出是否符合预期的红黑树性质。

疑难解答

  • 问题:红黑树不平衡?

    • 可能旋转和重新着色逻辑有误,检查 fixViolation 方法。
  • 问题:遇到段错误?

    • 检查指针操作,确保没有对空指针进行非法访问。

总结

红黑树通过精巧的颜色和旋转规则保持良好的性能,是许多计算机程序中的重要组成部分。通过以上实现,可以深入理解其工作原理和应用场景。

未来展望

随着数据规模的增长和硬件的演进,对平衡树的需求将持续增加。其中,红黑树结合其他先进的数据结构(如跳表、B树等),将在大数据、数据库设计和系统优化中继续扮演重要角色。探索如何在多核和分布式环境中优化红黑树也是未来的研究方向之一。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。