c++实现简单红黑树

红黑树是一种自平衡二叉查找树,它能够保证在最坏情况下基本的动态集合操作的时间复杂度为O(log n),其中n是树中的节点数。红黑树的每个节点都包含一个额外的颜色位,表示节点是红色还是黑色。红黑树的一些主要特性和操作如下:

红黑树的特性

1. 每个节点是红色或黑色。

2. 根节点是黑色。

3. 所有叶子节点是黑色。

4. 如果一个节点是红色的,则它的两个子节点都是黑色的。

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

其中第四点不难看出了:

  1. 红色节点的父节点都是黑色
  2. 从根节点到叶子节点的所有路径上不能有 2 个连续的红色节点

这些特性确保了红黑树的高度近似平衡,从而保证了基本操作的时间复杂度为 O(log n)。

红黑树中有一些基本操作如:

旋转操作:

旋转是红黑树中非常重要的操作,用于维持树的平衡。旋转分为左旋和右旋。

 插入操作:

插入新节点后,可能会违反红黑树的性质,需要进行修复。插入操作包括以下步骤:
1. 将新节点插入红黑树,并将其着色为红色。
2. 修复红黑树的性质。

删除操作:

删除节点后,同样可能会违反红黑树的性质,需要进行修复。删除操作包括以下步骤:
1. 找到并删除节点。
2. 修复红黑树的性质。

红黑树在计算机科学中有广泛的应用。由于其高效的查询、插入和删除操作,它在很多实际场景中被广泛使用。以下是一些红黑树常见的应用场景

1. 数据库系统

数据库系统需要高效地执行插入、删除和查找操作,以维护大量数据。红黑树由于其平衡特性,确保了这些操作在最坏情况下的时间复杂度为 O(log⁡n)O(\log n)O(logn),因此被广泛用于数据库索引(如 B+ 树的基础)和内存中的数据结构(如数据库事务管理中的锁管理)。

2. 操作系统内核

红黑树在操作系统内核中有多个应用,例如:

  • 进程调度:用于管理进程的调度队列,确保高效地插入、删除和查找进程。
  • 内存管理:用于管理虚拟内存区域,跟踪空闲和已分配的内存块。

3. 高性能缓存

在缓存系统中,红黑树用于实现高效的缓存替换策略,例如 Least Recently Used (LRU) 缓存。红黑树帮助实现快速的插入、删除和查找缓存条目。

4. 网络路由

在网络路由协议(如 OSPF 和 BGP)中,红黑树用于维护路由表和前缀匹配表,以支持快速的路由查找和更新操作。

5. 集合和映射容器

红黑树在许多编程语言的标准库中实现集合(Set)和映射(Map)容器,例如:C++ STLstd::setstd::map 都是基于红黑树实现的。

6. 动态顺序统计

红黑树可以扩展用于动态顺序统计问题,例如找到序列中的第 k 大元素或求区间的和。这种扩展通常通过在节点中存储额外的信息(如子树大小或子树和)来实现。

下面是一个使用cpp实现红黑树的示例,实现了一个简单的红黑树,包含了一些基本功能,如插入删除,旋转,并提供了查找第 k 大元素的功能:

#include <iostream>
#include <limits>

enum Color { RED, BLACK };

// 定义节点结构体
struct Node {
    int data;     // 数据
    Color color;  // 颜色
    Node *left, *right, *parent; // 左子节点,右子节点和父节点
    int size;     // 子树大小

    // 构造函数
    Node(int data) : data(data), color(RED), left(nullptr), right(nullptr), parent(nullptr), size(1) {}
};

class RedBlackTree {
private:
    Node *root; // 根节点

    // 左旋操作
    void rotateLeft(Node *&root, Node *&pt);
    // 右旋操作
    void rotateRight(Node *&root, Node *&pt);
    // 插入修复操作
    void fixInsert(Node *&root, Node *&pt);
    // 二叉搜索树的插入操作
    Node* BSTInsert(Node* root, Node* pt);
    // 更新节点的子树大小
    void updateSize(Node *node);
    // 查找第 k 大元素
    Node* select(Node* node, int k);

public:
    RedBlackTree() { root = nullptr; } // 构造函数初始化根节点为空
    void insert(const int &data); // 插入操作
    void inorder(); // 中序遍历
    void inorderHelper(Node *root); // 中序遍历的辅助函数
    Node* findKthLargest(int k); // 查找第 k 大元素
};

// 左旋操作
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; // 更新父节点
    updateSize(pt);        // 更新子树大小
    updateSize(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; // 更新父节点
    updateSize(pt);        // 更新子树大小
    updateSize(pt_left);   // 更新子树大小
}

// 插入修复操作
void RedBlackTree::fixInsert(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;

            // 情况 1:叔叔节点是红色
            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 {
                // 情况 2:叔叔节点是黑色,当前节点是右子节点
                if (pt == parent_pt->right) {
                    rotateLeft(root, parent_pt);
                    pt = parent_pt;
                    parent_pt = pt->parent;
                }
                // 情况 3:叔叔节点是黑色,当前节点是左子节点
                rotateRight(root, grand_parent_pt);
                swap(parent_pt->color, grand_parent_pt->color);
                pt = parent_pt;
            }
        }
        // 父节点是祖父节点的右子节点
        else {
            Node *uncle_pt = grand_parent_pt->left;

            // 情况 1:叔叔节点是红色
            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 {
                // 情况 2:叔叔节点是黑色,当前节点是左子节点
                if (pt == parent_pt->left) {
                    rotateRight(root, parent_pt);
                    pt = parent_pt;
                    parent_pt = pt->parent;
                }
                // 情况 3:叔叔节点是黑色,当前节点是右子节点
                rotateLeft(root, grand_parent_pt);
                swap(parent_pt->color, grand_parent_pt->color);
                pt = parent_pt;
            }
        }
    }
    root->color = BLACK; // 确保根节点是黑色
}

// 更新节点的子树大小
void RedBlackTree::updateSize(Node *node) {
    if (node != nullptr) {
        node->size = 1; // 当前节点计为 1
        if (node->left != nullptr) {
            node->size += node->left->size; // 加上左子树的大小
        }
        if (node->right != nullptr) {
            node->size += node->right->size; // 加上右子树的大小
        }
    }
}

// 二叉搜索树的插入操作
Node* RedBlackTree::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;
    }

    updateSize(root); // 更新子树大小
    return root;
}

// 插入操作
void RedBlackTree::insert(const int &data) {
    Node *pt = new Node(data); // 创建新节点
    root = BSTInsert(root, pt); // 插入节点
    fixInsert(root, pt); // 修复红黑树的性质
}

// 查找第 k 大元素
Node* RedBlackTree::select(Node* node, int k) {
    int leftSize = (node->left != nullptr) ? node->left->size : 0; // 获取左子树的大小
    int rank = leftSize + 1; // 当前节点的排名

    if (k == rank) return node; // 找到第 k 大元素
    else if (k < rank) return select(node->left, k); // 在左子树中查找
    else return select(node->right, k - rank); // 在右子树中查找
}

// 查找第 k 大元素
Node* RedBlackTree::findKthLargest(int k) {
    return select(root, k);
}

// 中序遍历
void RedBlackTree::inorder() { inorderHelper(root); }

// 中序遍历的辅助函数
void RedBlackTree::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.inorder();
    std::cout << std::endl;

    int k = 2;
    Node* kthLargest = tree.findKthLargest(k);
    if (kthLargest != nullptr) {
        std::cout << "第 " << k << " 大的元素是 " << kthLargest->data << std::endl;
    } else {
        std::cout << "未找到第 " << k << " 大的元素" << std::endl;
    }

    return 0;
}

  • 37
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值