C++实现红黑树应用实例代码

C++实现红黑树应用实例代码

什么是红黑树

红黑树(Red-Black Tree)是一种自平衡二叉查找树,在C++中的STL中的set和map就是基于红黑树实现的。红黑树满足以下性质:

  1. 每个节点或者是黑色,或者是红色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL节点,空节点)是黑色的。
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的。
  5. 对于任意一个节点而言,其到叶子节点NIL的任何路径上包含的黑色节点个数相同。

通过以上性质,可以保证红黑树的树高不超过 $2log_2n$ ,其中 $n$ 为节点个数。

C++代码实现

结构体定义

首先我们定义红黑树的节点结构体:

enum Color{ RED, BLACK };

template <class T>
struct RBTreeNode
{
    Color color;
    T key;
    RBTreeNode<T>* parent;
    RBTreeNode<T>* left;
    RBTreeNode<T>* right;

    RBTreeNode(T data, Color c = Color::RED, RBTreeNode<T>* p = nullptr,
        RBTreeNode<T>* l = nullptr, RBTreeNode<T>* r = nullptr) :
        key(data), color(c), parent(p), left(l), right(r) {}
};

我们使用枚举类型 Color 来代表节点颜色,节点中包含了当前节点的颜色、关键字信息、父节点指针、左子树指针和右子树指针。

插入节点

插入节点的过程中,我们需要通过比较关键字大小判断插入的位置。插入完成后,红黑树可能会不满足黑色节点数目相同的性质,因此我们需要对红黑树进行一系列转换,保证性质得以满足。

template <class T>
void RBTree<T>::insert(RBTreeNode<T>* node)
{
    RBTreeNode<T>* ptrNode = root;
    RBTreeNode<T>* parentNode = nullptr;

    while (ptrNode != nullptr)
    {
        parentNode = ptrNode;

        if (node->key < ptrNode->key)
        {
            ptrNode = ptrNode->left;
        }
        else
        {
            ptrNode = ptrNode->right;
        }
    }

    node->parent = parentNode;

    if (parentNode == nullptr)
    {
        root = node;
    }
    else if (node->key < parentNode->key)
    {
        parentNode->left = node;
    }
    else
    {
        parentNode->right = node;
    }

    node->color = Color::RED;

    fixupInsert(node);
}

插入修复

为了修正插入节点引起的变化,我们需要进行一些修复操作:

template <class T>
void RBTree<T>::fixupInsert(RBTreeNode<T>* node)
{
    RBTreeNode<T>* parentNode = nullptr;
    RBTreeNode<T>* grandNode = nullptr;

    while (node->parent != nullptr && node->parent->color == Color::RED)
    {
        parentNode = node->parent;
        grandNode = parentNode->parent;

        if (parentNode == grandNode->left)
        {
            RBTreeNode<T>* nodeUncle = grandNode->right;

            // 情况1
            if (nodeUncle != nullptr && nodeUncle->color == Color::RED)
            {
                parentNode->color = Color::BLACK;
                nodeUncle->color = Color::BLACK;
                grandNode->color = Color::RED;

                node = grandNode;
            }
            else
            {
                // 情况2
                if (node == parentNode->right)
                {
                    leftRotate(parentNode);
                    std::swap(node, parentNode);
                }

                // 情况3
                parentNode->color = Color::BLACK;
                grandNode->color = Color::RED;

                rightRotate(grandNode);
            }
        }
        else
        {
            RBTreeNode<T>* nodeUncle = grandNode->left;

            // 情况1
            if (nodeUncle != nullptr && nodeUncle->color == Color::RED)
            {
                parentNode->color = Color::BLACK;
                nodeUncle->color = Color::BLACK;
                grandNode->color = Color::RED;

                node = grandNode;
            }
            else
            {
                // 情况2
                if (node == parentNode->left)
                {
                    rightRotate(parentNode);
                    std::swap(node, parentNode);
                }

                // 情况3
                parentNode->color = Color::BLACK;
                grandNode->color = Color::RED;

                leftRotate(grandNode);
            }
        }
    }

    root->color = Color::BLACK;
}

左旋和右旋

左旋和右旋是红黑树的基本操作:

template <class T>
void RBTree<T>::leftRotate(RBTreeNode<T>* node)
{
    RBTreeNode<T>* rightChild = node->right;

    node->right = rightChild->left;

    if (rightChild->left != nullptr)
    {
        rightChild->left->parent = node;
    }

    rightChild->parent = node->parent;

    if (node->parent == nullptr)
    {
        root = rightChild;
    }
    else if (node == node->parent->left)
    {
        node->parent->left = rightChild;
    }
    else
    {
        node->parent->right = rightChild;
    }

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

template <class T>
void RBTree<T>::rightRotate(RBTreeNode<T>* node)
{
    RBTreeNode<T>* leftChild = node->left;

    node->left = leftChild->right;

    if (leftChild->right != nullptr)
    {
        leftChild->right->parent = node;
    }

    leftChild->parent = node->parent;

    if (node->parent == nullptr)
    {
        root = leftChild;
    }
    else if (node == node->parent->left)
    {
        node->parent->left = leftChild;
    }
    else
    {
        node->parent->right = leftChild;
    }

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

示例

示例一:插入节点

以插入关键字为7的节点为例,我们先构造红黑树:

            (11B)
          /      \
        (2B)     (14R)
       /    \       \
    (1R)   (7R)     (15R)

插入关键字为7的节点,红色节点:

            (11B)
          /      \
        (2B)     (14R)
       /    \       \
    (1R)   (7R)     (15R)
              \
              (7R)

插入完成后修复红黑树,得到:

            (11B)
          /      \
        (2B)     (14B)
       /    \       \
    (1R)   (7B)     (15R)
              \
              (7R)

示例二:删除节点

以删除关键字为11的节点为例,我们先构造红黑树:

            (11B)
          /      \
        (2B)     (14R)
       /    \       \
    (1R)   (7R)     (15R)

删除关键字为11的节点,得到:

            (14R)
          /      \
        (2B)     (15B)
       /    \
    (1R)   (7R)

删除完成后我们需要对红黑树进行一系列修复操作,最终得到:

            (2B)
          /      \
        (1R)     (14B)
                /    \
              (7R)   (15R)

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++实现红黑树应用实例代码 - Python技术站

(0)
上一篇 2023年5月24日
下一篇 2023年5月24日

相关文章

  • C++11 并发指南之std::mutex详解

    C++11 并发指南之std::mutex详解 什么是std::mutex? std::mutex是C++11标准中一个用于保护共享数据的同步原语。它是一个轻量级的锁,可以用于实现临界段或者锁保护的互斥访问。当一个线程执行到std::mutex的lock()方法时,如果此前该锁已经被另一个线程占用,那么该线程会被挂起,直到该锁被释放为止。 std::mute…

    C 2023年5月22日
    00
  • ajax处理返回的json格式数据方法

    下面我会给你详细讲解“ajax处理返回的json格式数据方法”的完整攻略。 步骤一:发起ajax请求 在网页中使用ajax处理json数据通常需要调取服务器端的api,通过发起ajax请求获取json数据。发起ajax请求可以使用像jquery这样的第三方库,以下是一个发起ajax请求的范例代码: $.ajax({ url: ‘/api/getData’, …

    C 2023年5月23日
    00
  • C语言实现图书管理系统开发

    C语言实现图书管理系统开发攻略 1. 程序设计 图书管理系统是一个比较复杂的系统,需要多个模块进行协同工作,因此我们需要仔细设计整个系统的流程。 1.1 系统流程 在设计图书管理系统时,需要考虑以下几个方面的流程: 图书管理:包括图书的增加、删除、修改和查询等操作; 读者管理:包括读者的信息录入、修改和查询等操作; 借还管理:包括图书的借阅和归还等操作。 1…

    C 2023年5月23日
    00
  • C语言实现随机抽取纸牌程序

    下面我会详细讲解“C语言实现随机抽取纸牌程序”的完整攻略,过程中也会提供两个示例说明。 随机生成整副牌 首先,我们需要随机生成一整副牌。在C语言中,我们可以用一个长度为52的数组来表示整副牌,根据花色和点数生成每张牌。 int deck[52]; int i, j, k; for (i = 0; i < 4; i++) { for (j = 0; j …

    C 2023年5月22日
    00
  • C语言实现爆炸展开的扫雷详解

    C语言实现爆炸展开的扫雷详解 什么是扫雷游戏? 扫雷是一款非常经典的单机游戏,也是Windows操作系统自带的经典小游戏之一。在游戏中,玩家需要打开一个地图,为了避免触雷,需要根据数字提示来判断周围的方块是否是地雷,最终将地图上的所有地雷都标记出来。 怎么实现爆炸展开? “爆炸展开”是扫雷游戏中非常重要的一步,也是难度比较大的一部分。如果一个方块周围没有地雷…

    C 2023年5月23日
    00
  • win8.1系统安装软件后重复提示”应用程序发生异常”的解决方法

    下面我将分享一下“win8.1系统安装软件后重复提示’应用程序发生异常’的解决方法”,具体攻略如下: 1. 清理残余文件和注册表项 卸载软件时,很多时候都不是完全干净的,留下了很多不必要的残余文件和注册表项,这些就可能会导致应用程序发生异常。因此,我们可以采取以下步骤进行清理: 打开控制面板,点击程序和功能。 在程序和功能列表中找到相关的软件,右键点击并选择…

    C 2023年5月23日
    00
  • C语言中回调函数的含义与使用场景详解

    C语言中回调函数的含义与使用场景详解 什么是回调函数? C语言中,回调函数是指一个传入另一个函数作为参数的函数。这个传入的函数在另一个函数内部被调用。换句话说,回调函数是一种通过函数指针的技术来实现的函数间的回调。 具体来说,当一个函数调用另一个函数并向其中传递一个函数指针作为参数时,被传递的函数就被称为回调函数。 回调函数的使用场景 1. 事件回调 事件回…

    C 2023年5月24日
    00
  • Go 语言 json解析框架与 gjson 详解

    Go 语言 json解析框架与 gjson 详解 介绍 在 Golang 中,解析 JSON 数据是一项非常常见的任务。Go提供了标准的JSON包,可以轻松地将JSON数据编组和解组。但是,在使用标准JSON包解析大型复杂JSON结构时,可能存在些许不足,例如代码冗余,性能瓶颈等问题。针对这些问题,目前有许多优秀的JSON解析框架,GJSON是其中一个很不错…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部