C++ 红黑树

打印 上一主题 下一主题

主题 679|帖子 679|积分 2037

目录
  
  ​
  0.媒介
  1.红黑树概念
  2.红黑树性质
  3.红黑树节点定义
  节点属性详解
  4.红黑树结构
  4.1带头节点的红黑树结构
  4.2不带头节点的红黑树结构
  5.红黑树插入节点操作
  5.1 按照二叉搜刮树的规则插入新节点
  5.2 检测新节点插入后,红黑树的性质是否遭到粉碎
  5.2.1 环境一: cur为红,p为红,g为黑,u存在且为红
  5.2.2 环境二: cur为红,p为红,g为黑,u不存在/u存在且为黑(需要单旋)
  5.2.3 环境三: cur为红,p为红,g为黑,u不存在/u存在且为黑(需要双旋)
  6.红黑树删除节点操作
  6.1 按照二叉搜刮树的规则删除节点
  6.2. 检测删除节点后,红黑树的性质是否遭到粉碎,并进行修复
  7.红黑树的性能
  7.1红黑树的复杂度分析
  7.2与 AVL 树的比力
  8.红黑树的迭代器设计
  8.1迭代器结构
  8.2前向迭代(operator++)
  8.3后向迭代(operator--)
  9.红黑树的模拟实现代码
  10.基于红黑树的map模拟实现
  11.结语
  
  
  


(图像由AI天生) 
0.媒介

在之前的文章中,我们先容了 C++ 尺度库中的 map 和 set 容器的使用,以及 AVL 树的实现。尽管 AVL 树在均衡性方面表现优秀,但在插入和删除操作频仍的应用中,红黑树(Red-Black Tree)由于其较少的旋转操作次数,每每能提供更优的性能。本篇博客将详细先容红黑树的概念、性质、节点定义、结构、插入与删除操作、性能、迭代器设计,并展示基于红黑树的模拟实现代码及其在 map 容器中的应用。
1.红黑树概念

红黑树(Red-Black Tree)是一种自均衡二叉搜刮树,在每个节点上增长一个存储位表示节点的颜色,可以是红色(Red)或玄色(Black)。红黑树通过对从根到叶子的路径上各个节点的着色方式进行限制,确保没有任何一条路径比其他路径长出两倍,从而实现近似的均衡。
红黑树最早由 Rudolf Bayer 于 1972 年提出,最初被称为对称二叉 B 树(Symmetric Binary B-trees)。厥后,Leonidas J. Guibas 和 Robert Sedgewick 对其进行了改进和推广,正式提出了红黑树的概念。红黑树的设计思想是通过简单的规则和操作,确保树在插入和删除操作后保持均衡,从而提供高效的查找性能。
红黑树广泛应用于各种实际场景中,其性质使得它在实现高效数据结构时具有很大优势。比方:


  • STL 容器:C++ 尺度模板库(STL)中的 map 和 set 容器通常基于红黑树实现,以保证快速的插入、删除和查找操作。
  • 数据库索引:很多数据库系统使用红黑树来实现索引结构,以提高数据检索的服从。
  • 内核调理:一些操作系统内核使用红黑树来管理进程调理,以确保系统能够高效地处理任务。
2.红黑树性质


(图片泉源:知乎@王大帅 特此鸣谢) 
红黑树具有以下五个重要性质,这些性质保证了红黑树的均衡性和高效性:

  • 每个节点不是红色就是玄色

    • 红黑树的每个节点都有一个颜色属性,这个颜色要么是红色,要么是玄色。通过颜色属性的限制,红黑树能够在结构上保持均衡。

  • 根节点是玄色的

    • 红黑树的根节点始终是玄色的。这一性质确保了树的均衡性从根节点开始,并且为树的其他均衡规则提供了底子。

  • 如果一个节点是红色的,则它的两个孩子节点是玄色的

    • 这一性质制止了两个连续的红色节点出如今从根到叶子的路径上。通过限制红色节点的排列方式,红黑树能够防止路径长度的不均衡增长。

  • 对于每个节点,从该节点到其全部子女叶节点的简单路径上,均包罗相同数目的玄色节点

    • 这一性质也称为玄色均衡性(black-height)。它保证了从任一节点到其叶节点的路径长度相似,从而使红黑树接近均衡。这意味着在插入或删除节点时,红黑树可以通过重新着色和旋转操作来恢复均衡,而不需要像 AVL 树那样频仍调解。

  • 每个叶子节点都是玄色的(此处的叶子节点指的是空节点)

    • 红黑树中的叶子节点实际上是树中的空节点(NIL 节点),这些节点也被视为玄色。即使树中没有显式存储这些 NIL 节点,明白它们的存在对于分析红黑树的均衡性是至关重要的。

3.红黑树节点定义

在红黑树中,每个节点不仅存储数据,还包罗指向其子节点和父节点的指针,以及节点的颜色属性。下面是红黑树节点的定义代码:
  1. enum Color { RED, BLACK };
  2. template<class T>
  3. struct RBTreeNode
  4. {
  5.     T _data;  // 存储的数据
  6.     RBTreeNode<T>* _left;  // 指向左子节点的指针
  7.     RBTreeNode<T>* _right;  // 指向右子节点的指针
  8.     RBTreeNode<T>* _parent;  // 指向父节点的指针
  9.     Color _color;  // 节点的颜色
  10.     // 构造函数,初始化节点的数据和指针,默认颜色为红色
  11.     RBTreeNode(const T& data)
  12.         : _data(data)
  13.         , _left(nullptr)
  14.         , _right(nullptr)
  15.         , _parent(nullptr)
  16.         , _color(RED)
  17.     {}
  18. };
复制代码
节点属性详解


  • _data:

    • 存储节点的数据。这个数据可以是任何范例,由模板参数 T 决定。

  • _left:

    • 指向左子节点的指针。如果左子节点不存在,则该指针为 nullptr。

  • _right:

    • 指向右子节点的指针。如果右子节点不存在,则该指针为 nullptr。

  • _parent:

    • 指向父节点的指针。这在红黑树的插入和删除操作中非常重要,因为这些操作需要通过父节点来进行旋转和重新着色。

  • _color:

    • 节点的颜色属性,可以是红色(RED)或玄色(BLACK)。颜色属性在保持红黑树的均衡性中起到关键作用。
    • 在构造函数中,节点的颜色被默认设置为红色(RED)。这是因为插入新节点时,默认环境下设置为红色更易于保持树的均衡,并通过后续的旋转和重新着色操作来调解树的结构。

4.红黑树结构

红黑树可以带有头节点(header)或者不带头节点。在带头节点的红黑树结构中,头节点提供了便利的指针,可以快速访问树的最小节点、最大节点以及根节点。这种设计在实现中有助于简化边界环境的处理。
4.1带头节点的红黑树结构

带头节点的红黑树使用一个特殊的头节点(header),它的颜色通常设为红色,并且其指针指向树中的特殊节点。详细来说,头节点的指针结构如下:


  • header->parent 指向树的根节点。
  • header->left 指向树中最小的节点(leftmost)。
  • header->right 指向树中最大的节点(rightmost)。
4.2不带头节点的红黑树结构

不带头节点的红黑树则不使用额外的头节点,直接通过根节点进行操作。在这种结构中,树的边界处理和遍历操作相对复杂一些,因为没有头节点来存储额外的指针信息。
为定义方便起见,后文中红黑树结构采用无头结点方式。
5.红黑树插入节点操作

红黑树是在二叉搜刮树的底子上加上其均衡限制条件,因此红黑树的插入操作可以分为两个步骤:

  • 按照二叉搜刮树的规则插入新节点
  • 检测新节点插入后,红黑树的性质是否遭到粉碎,并进行修复
5.1 按照二叉搜刮树的规则插入新节点

首先,我们按照二叉搜刮树的规则找到新节点的插入位置,并将其插入到树中。插入的新节点默认颜色为红色。以下是详细的实现代码:
  1. pair<Iterator, bool> Insert(const T& data) {
  2.     if (_root == nullptr) {
  3.         _root = new Node(data);
  4.         _root->_color = BLACK;  // 根节点必须是黑色
  5.         return make_pair(Iterator(_root, _root), true);
  6.     }
  7.     KeyOfT kot;  // 获取键值
  8.     Node* parent = nullptr;
  9.     Node* cur = _root;
  10.     while (cur) {
  11.         if (kot(cur->_data) == kot(data)) {
  12.             return make_pair(Iterator(cur, _root), false);  // 如果数据已经存在,直接返回
  13.         }
  14.         parent = cur;
  15.         if (kot(cur->_data) > kot(data)) {
  16.             cur = cur->_left;
  17.         } else {
  18.             cur = cur->_right;
  19.         }
  20.     }
  21.     cur = new Node(data);
  22.     Node* newNode = cur;
  23.     if (KeyOfT()(data) < KeyOfT()(parent->_data)) {
  24.         parent->_left = cur;
  25.     } else {
  26.         parent->_right = cur;
  27.     }
  28.     cur->_parent = parent;
  29.     // 检测并修复红黑树性质,伪代码
  30.     FixInsert(cur);
  31.     return make_pair(Iterator(newNode, _root), true);
  32. }
复制代码
5.2 检测新节点插入后,红黑树的性质是否遭到粉碎

在插入节点后,可能会粉碎红黑树的性质,需要进行修复。红黑树的性质有五条:

  • 每个节点不是红色就是玄色。
  • 根节点是玄色的。
  • 如果一个节点是红色的,则它的两个孩子节点是玄色的。
  • 对于每个节点,从该节点到其全部子女叶节点的简单路径上,均包罗相同数目的玄色节点。
  • 每个叶子节点都是玄色的(此处的叶子节点指的是空节点)。
为了修复红黑树的性质,我们需要考虑以下几种环境:


  • 环境 1:新节点的父节点是玄色的。这种环境下,插入操作不会粉碎红黑树的任何性质,因此不需要进行任何操作。
  • 环境 2:新节点的父节点是红色的。由于红黑树的性质 3 被粉碎(两个连续的红色节点),我们需要进行修复操作。详细分为以下几种子环境:

    • 环境 2.1:新节点的叔叔节点(父节点的兄弟节点)是红色的。这种环境下,父节点和叔叔节点都变为玄色,祖父节点变为红色,然后将当前节点指向祖父节点,继续检测祖父节点。
    • 环境 2.2:新节点的叔叔节点是玄色的,且新节点是父节点的右孩子。此时,我们需要进行左旋操作,将新节点变成父节点,然后进行环境 2.3 的处理。
    • 环境 2.3:新节点的叔叔节点是玄色的,且新节点是父节点的左孩子。这种环境下,我们进行右旋操作,将父节点变成新节点,调解颜色后结束修复。

我们不妨约定cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点。
5.2.1 环境一: cur为红,p为红,g为黑,u存在且为红

在这种环境下,当前节点cur的父节点p和叔叔节点u都是红色,祖父节点g是玄色。这种环境粉碎了红黑树性质3(红节点的子节点必须是玄色)。解决方式如下:

  • 将p和u改为玄色。
  • 将g改为红色。
  • 将当前节点cur移动到g,继续向上调解。
  1. void FixInsert(Node* node) {
  2.     Node* parent = nullptr;
  3.     Node* grandFather = nullptr;
  4.     // 当前节点不在根节点且其父节点为红色时,需要调整
  5.     while (node != _root && node->_parent->_color == RED) {
  6.         parent = node->_parent;
  7.         grandFather = parent->_parent;
  8.         if (parent == grandFather->_left) {
  9.             Node* uncle = grandFather->_right;
  10.             if (uncle && uncle->_color == RED) {
  11.                 // 情况 1: 叔叔是红色
  12.                 parent->_color = BLACK;
  13.                 uncle->_color = BLACK;
  14.                 grandFather->_color = RED;
  15.                 node = grandFather; // 将当前节点上移到祖父节点继续调整
  16.             } else {
  17.                 // 处理情况 2 和 3
  18.             }
  19.         } else {
  20.             Node* uncle = grandFather->_left;
  21.             if (uncle && uncle->_color == RED) {
  22.                 // 情况 1: 叔叔是红色
  23.                 parent->_color = BLACK;
  24.                 uncle->_color = BLACK;
  25.                 grandFather->_color = RED;
  26.                 node = grandFather; // 将当前节点上移到祖父节点继续调整
  27.             } else {
  28.                 // 处理情况 2 和 3
  29.             }
  30.         }
  31.     }
  32.     _root->_color = BLACK;  // 根节点始终是黑色
  33. }
复制代码
5.2.2 环境二: cur为红,p为红,g为黑,u不存在/u存在且为黑(需要单旋)

在这种环境下,当前节点cur的父节点p是红色,叔叔节点u是玄色或不存在。根据cur和p的相对位置,需要进行单旋操作。


  • 如果cur是p的右子节点,p是g的左子节点,需要进行左旋。
  • 如果cur是p的左子节点,p是g的右子节点,需要进行右旋。
  1. void FixInsert(Node* node) {
  2.     Node* parent = nullptr;
  3.     Node* grandFather = nullptr;
  4.     // 当前节点不在根节点且其父节点为红色时,需要调整
  5.     while (node != _root && node->_parent->_color == RED) {
  6.         parent = node->_parent;
  7.         grandFather = parent->_parent;
  8.         if (parent == grandFather->_left) {
  9.             Node* uncle = grandFather->_right;
  10.             if (uncle && uncle->_color == RED) {
  11.                 parent->_color = BLACK;
  12.                 uncle->_color = BLACK;
  13.                 grandFather->_color = RED;
  14.                 node = grandFather; // 将当前节点上移到祖父节点继续调整
  15.             } else {
  16.                 if (node == parent->_right) {
  17.                     // 情况 2: 叔叔是黑色且当前节点是右子节点,需要左旋
  18.                     RotateL(parent);
  19.                     node = parent;
  20.                     parent = node->_parent;
  21.                 }
  22.                 // 单旋后调整颜色
  23.                 RotateR(grandFather);
  24.                 swap(parent->_color, grandFather->_color);
  25.                 node = parent;
  26.             }
  27.         } else {
  28.             Node* uncle = grandFather->_left;
  29.             if (uncle && uncle->_color == RED) {
  30.                 parent->_color = BLACK;
  31.                 uncle->_color = BLACK;
  32.                 grandFather->_color = RED;
  33.                 node = grandFather; // 将当前节点上移到祖父节点继续调整
  34.             } else {
  35.                 if (node == parent->_left) {
  36.                     // 情况 2: 叔叔是黑色且当前节点是左子节点,需要右旋
  37.                     RotateR(parent);
  38.                     node = parent;
  39.                     parent = node->_parent;
  40.                 }
  41.                 // 单旋后调整颜色
  42.                 RotateL(grandFather);
  43.                 swap(parent->_color, grandFather->_color);
  44.                 node = parent;
  45.             }
  46.         }
  47.     }
  48.     _root->_color = BLACK;  // 根节点始终是黑色
  49. }
复制代码

5.2.3 环境三: cur为红,p为红,g为黑,u不存在/u存在且为黑(需要双旋)

在这种环境下,当前节点cur的父节点p是红色,叔叔节点u是玄色或不存在。根据cur和p的相对位置,需要进行双旋操作。


  • 如果cur是p的左子节点,p是g的左子节点,且cur是p的右子节点(需要右旋后左旋)。
  • 如果cur是p的右子节点,p是g的右子节点,且cur是p的左子节点(需要左旋后右旋)。
  1. void FixInsert(Node* node) {
  2.     Node* parent = nullptr;
  3.     Node* grandFather = nullptr;
  4.     // 当前节点不在根节点且其父节点为红色时,需要调整
  5.     while (node != _root && node->_parent->_color == RED) {
  6.         parent = node->_parent;
  7.         grandFather = parent->_parent;
  8.         if (parent == grandFather->_left) {
  9.             Node* uncle = grandFather->_right;
  10.             if (uncle && uncle->_color == RED) {
  11.                 parent->_color = BLACK;
  12.                 uncle->_color = BLACK;
  13.                 grandFather->_color = RED;
  14.                 node = grandFather; // 将当前节点上移到祖父节点继续调整
  15.             } else {
  16.                 if (node == parent->_right) {
  17.                     // 情况 3: 叔叔是黑色且当前节点是右子节点,需要左旋后右旋
  18.                     RotateL(parent);
  19.                     node = parent;
  20.                     parent = node->_parent;
  21.                 }
  22.                 // 双旋后调整颜色
  23.                 RotateR(grandFather);
  24.                 swap(parent->_color, grandFather->_color);
  25.                 node = parent;
  26.             }
  27.         } else {
  28.             Node* uncle = grandFather->_left;
  29.             if (uncle && uncle->_color == RED) {
  30.                 parent->_color = BLACK;
  31.                 uncle->_color = BLACK;
  32.                 grandFather->_color = RED;
  33.                 node = grandFather; // 将当前节点上移到祖父节点继续调整
  34.             } else {
  35.                 if (node == parent->_left) {
  36.                     // 情况 3: 叔叔是黑色且当前节点是左子节点,需要右旋后左旋
  37.                     RotateR(parent);
  38.                     node = parent;
  39.                     parent = node->_parent;
  40.                 }
  41.                 // 双旋后调整颜色
  42.                 RotateL(grandFather);
  43.                 swap(parent->_color, grandFather->_color);
  44.                 node = parent;
  45.             }
  46.         }
  47.     }
  48.     _root->_color = BLACK;  // 根节点始终是黑色
  49. }
复制代码
6.红黑树删除节点操作

在红黑树中,删除节点操作分为两个部分:首先按照二叉搜刮树的规则删除节点,然后通过调解(旋转和重新着色)来修复可能粉碎的红黑树性质。
6.1 按照二叉搜刮树的规则删除节点

删除节点时,首先找到要删除的节点,并进行删除操作。如果节点有两个子节点,需要找到后继节点更换被删除节点,并删除后继节点。
  1. Node* Delete(Node* root, const T& data) {
  2.     // 查找并删除节点,返回新根节点
  3.     Node* z = FindNode(root, data);  // 找到要删除的节点
  4.     if (!z) return root;  // 节点不存在,直接返回
  5.     Node* y = z;
  6.     Node* x;
  7.     Color y_original_color = y->_color;
  8.     if (z->_left == nullptr) {
  9.         x = z->_right;
  10.         Transplant(root, z, z->_right);
  11.     } else if (z->_right == nullptr) {
  12.         x = z->_left;
  13.         Transplant(root, z, z->_left);
  14.     } else {
  15.         y = Minimum(z->_right);  // 找到后继节点
  16.         y_original_color = y->_color;
  17.         x = y->_right;
  18.         if (y->_parent == z) {
  19.             if (x) x->_parent = y;
  20.         } else {
  21.             Transplant(root, y, y->_right);
  22.             y->_right = z->_right;
  23.             y->_right->_parent = y;
  24.         }
  25.         Transplant(root, z, y);
  26.         y->_left = z->_left;
  27.         y->_left->_parent = y;
  28.         y->_color = z->_color;
  29.     }
  30.     delete z;
  31.     if (y_original_color == BLACK) {
  32.         FixDelete(root, x);
  33.     }
  34.     return root;
  35. }
复制代码
6.2. 检测删除节点后,红黑树的性质是否遭到粉碎,并进行修复

删除节点后,可能会粉碎红黑树的性质,需要进行修复。常见的调解环境如下:
环境一:当前节点x是红色或其父节点是红色


  • 不需要做任何调解,因为删除一个红色节点不会粉碎红黑树的性质。
环境二:当前节点x是玄色,其兄弟节点是红色


  • 将父节点变为红色,兄弟节点变为玄色,然后进行旋转,转为环境三或四进行处理。
环境三:当前节点x是玄色,其兄弟节点是玄色,兄弟节点的子节点都是玄色


  • 将兄弟节点变为红色,继续向上调解,直到根节点或调解完毕。
环境四:当前节点x是玄色,其兄弟节点是玄色,兄弟节点的一个子节点是红色


  • 根据兄弟节点子节点的位置,进行旋转和重新着色。
7.红黑树的性能

7.1红黑树的复杂度分析

红黑树是一种自均衡二叉搜刮树,能够确保在最坏环境下的操作复杂度为O(logn),此中 n 是树中节点的数目。这种性能保证源于红黑树的均衡性质,使得树的高度始终保持在 O(logn) 范围内。以下是对红黑树重要操作的复杂度分析:

  • 查找

    • 红黑树的查找操作与二叉搜刮树雷同,通过比力节点值从根节点逐层向下查找。由于红黑树的高度最多为 O(logn),因此查找操作的复杂度为O(logn)。

  • 插入

    • 插入操作首先按照二叉搜刮树的规则找到插入位置,复杂度为O(logn)。然后,通过重新着色和旋转来保持红黑树的均衡。每次插入操作最多需要进行两次旋转,因此插入操作的复杂度为 O(logn)。

  • 删除

    • 删除操作也首先按照二叉搜刮树的规则找到要删除的节点,复杂度为 O(logn)。删除后,通过重新着色和旋转来保持红黑树的均衡。每次删除操作最多需要进行三次旋转,因此删除操作的复杂度为O(logn)。

7.2与 AVL 树的比力

红黑树与 AVL 树都是自均衡二叉搜刮树,但它们在详细实现和性能特性上有所不同。以下是两者的比力:

  • 均衡性

    • AVL 树:高度均衡,确保每个节点的左右子树高度差最多为 1。这意味着 AVL 树通常比红黑树更加均衡。
    • 红黑树:通过颜色和旋转规则保持均衡,但允许更松散的均衡条件。这使得红黑树的高度可能稍高于 AVL 树,但仍旧在 O(logn) 范围内。

  • 插入和删除操作

    • AVL 树:由于严格的均衡条件,插入和删除操作可能需要进行较多的旋转。插入操作的平均旋转次数为 1.44 次,删除操作的平均旋转次数为 2.44 次。
    • 红黑树:由于较为宽松的均衡条件,插入和删除操作所需的旋转次数通常较少。插入操作最多需要进行两次旋转,删除操作最多需要进行三次旋转。

  • 查找性能

    • AVL 树:由于更严格的均衡条件,AVL 树的查找性能在理论上优于红黑树。然而,在实际应用中,这种性能差异通常并不显着,尤其是在数据规模较大时。

  • 实用场景

    • AVL 树:实用于查找操作较为频仍、插入和删除操作较少的场景,如数据库索引和只读数据结构。
    • 红黑树:实用于插入和删除操作较为频仍的场景,如操作系统的任务调理和动态集合操作。红黑树在这些场景中由于旋转次数较少,能够提供更好的整体性能。

8.红黑树的迭代器设计

红黑树的迭代器设计需要支持遍历树中的全部节点,并能够实行前向和后向遍历操作。迭代器在红黑树中的作用雷同于指针,能够指向树中的节点,并提供便捷的节点访问和遍历功能。
8.1迭代器结构

红黑树的迭代器通过模板参数支持泛型,并包罗当前节点和树根节点的指针。下面是迭代器的定义:
  1. template<class T, class Ref, class Ptr>
  2. struct RBTreeIterator
  3. {
  4.         typedef RBTreeNode<T> Node;
  5.         typedef RBTreeIterator<T, Ref, Ptr> Self;
  6.         Node* _node;  // 当前节点
  7.         Node* _root;  // 树根节点
  8.         RBTreeIterator(Node* node, Node* root)
  9.                 : _node(node)
  10.                 , _root(root)
  11.         {}
  12.         Self& operator++();//待实现
  13.         Self& operator--();//待实现
  14.         Ref operator*()
  15.         {
  16.                 return _node->_data;
  17.         }
  18.         Ptr operator->()
  19.         {
  20.                 return &_node->_data;
  21.         }
  22.         bool operator!= (const Self& s)
  23.         {
  24.                 return _node != s._node;
  25.         }
  26.         bool operator== (const Self& s)
  27.         {
  28.                 return _node == s._node;
  29.         }
  30. };
复制代码
8.2前向迭代(operator++)

前向迭代操作用于遍历树的下一个节点。根据当前节点的位置,前向迭代的实现分为两种环境:

  • 当前节点有右子树:如果当前节点有右子树,则下一个节点是右子树的最左节点。
  • 当前节点没有右子树:如果当前节点没有右子树,则沿着父节点向上移动,直到找到一个节点,该节点是其父节点的左子节点。这个父节点就是下一个节点。
  1. Self& operator++()
  2. {
  3.         if (_node->_right)
  4.         {
  5.                 // 当前节点有右子树,找到右子树的最左节点
  6.                 Node* leftMost = _node->_right;
  7.                 while (leftMost->_left)
  8.                 {
  9.                         leftMost = leftMost->_left;
  10.                 }
  11.                 _node = leftMost;
  12.         }
  13.         else
  14.         {
  15.                 // 当前节点没有右子树,向上找第一个是左子节点的祖先
  16.                 Node* cur = _node;
  17.                 Node* parent = cur->_parent;
  18.                 while (parent && cur == parent->_right)
  19.                 {
  20.                         cur = parent;
  21.                         parent = cur->_parent;
  22.                 }
  23.                 _node = parent;
  24.         }
  25.         return *this;
  26. }
复制代码
8.3后向迭代(operator--)

后向迭代操作用于遍历树的前一个节点。根据当前节点的位置,后向迭代的实现分为三种环境:

  • 当前节点是 end():如果当前节点是 end()(空节点),则下一个节点是整棵树的最右节点。
  • 当前节点有左子树:如果当前节点有左子树,则下一个节点是左子树的最右节点。
  • 当前节点没有左子树:如果当前节点没有左子树,则沿着父节点向上移动,直到找到一个节点,该节点是其父节点的右子节点。这个父节点就是下一个节点。
  1. Self& operator--()
  2. {
  3.         if (_node == nullptr) // end()
  4.         {
  5.                 // 当前节点是end(),找到最右节点
  6.                 Node* rightMost = _root;
  7.                 while (rightMost && rightMost->_right)
  8.                 {
  9.                         rightMost = rightMost->_right;
  10.                 }
  11.                 _node = rightMost;
  12.         }
  13.         else if (_node->_left)
  14.         {
  15.                 // 当前节点有左子树,找到左子树的最右节点
  16.                 Node* rightMost = _node->_left;
  17.                 while (rightMost->_right)
  18.                 {
  19.                         rightMost = rightMost->_right;
  20.                 }
  21.                 _node = rightMost;
  22.         }
  23.         else
  24.         {
  25.                 // 当前节点没有左子树,向上找第一个是右子节点的祖先
  26.                 Node* cur = _node;
  27.                 Node* parent = cur->_parent;
  28.                 while (parent && cur == parent->_left)
  29.                 {
  30.                         cur = parent;
  31.                         parent = cur->_parent;
  32.                 }
  33.                 _node = parent;
  34.         }
  35.         return *this;
  36. }
复制代码
9.红黑树的模拟实现代码

  1. #pragma once
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cassert>
  5. #include<vector>
  6. using namespace std;
  7. enum Color { RED, BLACK };
  8. template<class T>
  9. struct RBTreeNode
  10. {
  11.         T _data;
  12.         RBTreeNode<T>* _left;
  13.         RBTreeNode<T>* _right;
  14.         RBTreeNode<T>* _parent;
  15.         Color _color;
  16.         RBTreeNode(const T& data)
  17.                 :_data(data)
  18.                 , _left(nullptr)
  19.                 , _right(nullptr)
  20.                 , _parent(nullptr)
  21.                 , _color(RED)
  22.         {}
  23. };
  24. template<class T, class Ref, class Ptr>
  25. struct RBTreeIterator
  26. {
  27.         typedef RBTreeNode<T> Node;
  28.         typedef RBTreeIterator<T, Ref, Ptr> Self;
  29.         Node* _node;
  30.         Node* _root;
  31.         RBTreeIterator(Node* node, Node* root)
  32.                 :_node(node)
  33.                 , _root(root)
  34.         {}
  35.         Self& operator++()
  36.         {
  37.                 if (_node->_right)
  38.                 {
  39.                         // 右不为空,右子树最左节点就是中序第一个
  40.                         Node* leftMost = _node->_right;
  41.                         while (leftMost->_left)
  42.                         {
  43.                                 leftMost = leftMost->_left;
  44.                         }
  45.                         _node = leftMost;
  46.                 }
  47.                 else
  48.                 {
  49.                         // 孩子是父亲左的那个祖先
  50.                         Node* cur = _node;
  51.                         Node* parent = cur->_parent;
  52.                         while (parent && cur == parent->_right)
  53.                         {
  54.                                 cur = parent;
  55.                                 parent = cur->_parent;
  56.                         }
  57.                         _node = parent;
  58.                 }
  59.                 return *this;
  60.         }
  61.         Self& operator--()
  62.         {
  63.                 if (_node == nullptr) // end()
  64.                 {
  65.                         // --end(),特殊处理,走到中序最后一个节点,整棵树的最右节点
  66.                         Node* rightMost = _root;
  67.                         while (rightMost && rightMost->_right)
  68.                         {
  69.                                 rightMost = rightMost->_right;
  70.                         }
  71.                         _node = rightMost;
  72.                 }
  73.                 else if (_node->_left)
  74.                 {
  75.                         // 左子树不为空,中序左子树最后一个
  76.                         Node* rightMost = _node->_left;
  77.                         while (rightMost->_right)
  78.                         {
  79.                                 rightMost = rightMost->_right;
  80.                         }
  81.                         _node = rightMost;
  82.                 }
  83.                 else
  84.                 {
  85.                         // 孩子是父亲右的那个祖先
  86.                         Node* cur = _node;
  87.                         Node* parent = cur->_parent;
  88.                         while (parent && cur == parent->_left)
  89.                         {
  90.                                 cur = parent;
  91.                                 parent = cur->_parent;
  92.                         }
  93.                         _node = parent;
  94.                 }
  95.                 return *this;
  96.         }
  97.         Ref operator*()
  98.         {
  99.                 return _node->_data;
  100.         }
  101.         Ptr operator->()
  102.         {
  103.                 return &_node->_data;
  104.         }
  105.         bool operator!= (const Self& s)
  106.         {
  107.                 return _node != s._node;
  108.         }
  109.         bool operator== (const Self& s)
  110.         {
  111.                 return _node == s._node;
  112.         }
  113. };
  114. template<class K, class T,class KeyOfT>
  115. class RBTree
  116. {
  117.         typedef RBTreeNode<T> Node;
  118. private:
  119.         Node* _root = nullptr;
  120. public:
  121.         typedef RBTreeIterator<T, T&, T*> Iterator;
  122.         typedef RBTreeIterator<T, const T&, const T*> ConstIterator;
  123.         Iterator Begin()
  124.         {
  125.                 Node* cur = _root;
  126.                 while (cur && cur->_left)
  127.                 {
  128.                         cur = cur->_left;
  129.                 }
  130.                 return Iterator(cur, _root);
  131.         }
  132.         Iterator End()
  133.         {
  134.                 return Iterator(nullptr, _root);
  135.         }
  136.         ConstIterator Begin() const
  137.         {
  138.                 Node* cur = _root;
  139.                 while (cur && cur->_left)
  140.                 {
  141.                         cur = cur->_left;
  142.                 }
  143.                 return ConstIterator(cur, _root);
  144.         }
  145.         ConstIterator End() const
  146.         {
  147.                 return ConstIterator(nullptr, _root);
  148.         }
  149.         RBTree() = default;
  150.         RBTree(const RBTree& t)
  151.         {
  152.                 _root = _Copy(t._root);
  153.         }
  154.         RBTree& operator=(RBTree t)
  155.         {
  156.                 swap(_root, t._root);//交换根节点
  157.                 return *this;
  158.         }
  159.         ~RBTree()
  160.         {
  161.                 _Destroy(_root);
  162.                 _root = nullptr;
  163.         }
  164.         pair<Iterator, bool> Insert(const T& data)
  165.         {
  166.                 if (_root == nullptr)
  167.                 {
  168.                         _root = new Node(data);
  169.                         _root->_color = BLACK;
  170.                         return make_pair(Iterator(_root, _root), true);
  171.                 }
  172.                 KeyOfT kot;//获取键值
  173.                 Node* parent = nullptr;
  174.                 Node* cur = _root;
  175.                 while (cur)
  176.                 {
  177.                         if (kot(cur->_data) == kot(data))
  178.                         {
  179.                                 return make_pair(Iterator(cur, _root), false);
  180.                         }
  181.                         parent = cur;
  182.                         if (kot(cur->_data) > kot(data))
  183.                         {
  184.                                 cur = cur->_left;
  185.                         }
  186.                         else //kot(cur->_data) > kot(data)
  187.                         {
  188.                                 cur = cur->_right;
  189.                         }
  190.                 }
  191.                 cur = new Node(data);
  192.                 Node* newNode = cur;
  193.                 if (KeyOfT()(data) < KeyOfT()(parent->_data))
  194.                 {
  195.                         parent->_left = cur;
  196.                 }
  197.                 else
  198.                 {
  199.                         parent->_right = cur;
  200.                 }
  201.                 cur->_parent = parent;
  202.                 while (parent && parent->_color == RED)
  203.                 {
  204.                         Node* grandFather = parent->_parent;
  205.                         //   g
  206.                         //  / \
  207.                         // p   u
  208.                         if (parent == grandFather->_left)
  209.                         {
  210.                                 Node* uncle = grandFather->_right;
  211.                                 if (uncle && uncle->_color == RED)
  212.                                 {
  213.                                         // 叔叔是红色,变色再继续向上调整
  214.                                         parent->_color = BLACK;
  215.                                         uncle->_color = BLACK;
  216.                                         grandFather->_color = RED;
  217.                                         cur = grandFather;
  218.                                         parent = cur->_parent;
  219.                                 }
  220.                                 else
  221.                                 {
  222.                                         // 叔叔是黑色/叔叔为空,旋转+变色
  223.                                         if (cur == parent->_left)
  224.                                         {
  225.                                                 //    g
  226.                                                 //   / \
  227.                                                 //  p   u
  228.                                                 // /
  229.                                                 //c
  230.                                                 RotateR(grandFather);
  231.                                                 parent->_color = BLACK;
  232.                                                 grandFather->_color = RED;
  233.                                         }
  234.                                         else
  235.                                         {
  236.                                                 //    g
  237.                                                 //   / \
  238.                                                 //  p   u
  239.                                                 //   \
  240.                                                 //    c
  241.                                                 RotateL(parent);
  242.                                                 RotateR(grandFather);
  243.                                                 cur->_color = BLACK;
  244.                                                 grandFather->_color = RED;
  245.                                         }
  246.                                         break;
  247.                                 }
  248.                         }
  249.                         else
  250.                         {
  251.                                 //   g
  252.                                 //  / \
  253.                                 // u   p
  254.                                 Node* uncle = grandFather->_left;
  255.                                 // 叔叔是红色,变色再继续向上调整
  256.                                 if (uncle && uncle->_color == RED)
  257.                                 {
  258.                                         parent->_color = BLACK;
  259.                                         uncle->_color = BLACK;
  260.                                         grandFather->_color = RED;
  261.                                         cur = grandFather;
  262.                                         parent = cur->_parent;
  263.                                 }
  264.                                 else // 叔叔是黑色/叔叔为空,旋转+变色
  265.                                 {
  266.                                         //          g
  267.                                         //         / \
  268.                                         //        u   p
  269.                                         //             \
  270.                                         //              c
  271.                                         if (cur == parent->_right)
  272.                                         {
  273.                                                 RotateL(grandFather);
  274.                                                 parent->_color = BLACK;
  275.                                                 grandFather->_color = RED;
  276.                                         }
  277.                                         else
  278.                                         {
  279.                                                 //          g
  280.                                                 //         / \
  281.                                                 //        u   p
  282.                                                 //           /
  283.                                                 //          c
  284.                                                 RotateR(parent);
  285.                                                 //          g
  286.                                                 //         / \
  287.                                                 //        u   c
  288.                                                 //             \
  289.                                                 //              p
  290.                                                 RotateL(grandFather);
  291.                                                 cur->_color = BLACK;
  292.                                                 grandFather->_color = RED;
  293.                                         }
  294.                                         break;
  295.                                 }
  296.                         }
  297.                 }
  298.                 _root->_color = BLACK;
  299.                 return make_pair(Iterator(newNode, _root), true);
  300.         }
  301.         void InOrder()
  302.         {
  303.                 _InOrder(_root);
  304.                 cout << endl;
  305.         }
  306.         int Size()
  307.         {
  308.                 return _Size(_root);
  309.         }
  310.         int Height()
  311.         {
  312.                 return _Height(_root);
  313.         }
  314. private:
  315.         Node* _Copy(Node* root)
  316.         {
  317.                 if (root == nullptr)
  318.                         return nullptr;
  319.                 Node* newRoot = new Node(root->_data);
  320.                 newRoot->_color = root->_color;
  321.                 newRoot->_left = _Copy(root->_left);
  322.                 newRoot->_right = _Copy(root->_right);
  323.                 if (newRoot->_left)
  324.                         newRoot->_left->_parent = newRoot;
  325.                 if (newRoot->_right)
  326.                         newRoot->_right->_parent = newRoot;
  327.                 return newRoot;
  328.         }
  329.         void _Destroy(Node* root)
  330.         {
  331.                 if (root == nullptr)
  332.                         return;
  333.                 _Destroy(root->_left);
  334.                 _Destroy(root->_right);
  335.                 delete root;
  336.         }
  337.         void _InOrder(Node* root)
  338.         {
  339.                 if (root == nullptr)
  340.                         return;
  341.                 _InOrder(root->_left);
  342.                 //cout << root->_kv.first << " " << root->_kv.second << endl;
  343.                 cout<<root->_data<<" ";
  344.                 _InOrder(root->_right);
  345.         }
  346.         int _Size(Node* root)
  347.         {
  348.                 if (root == nullptr)
  349.                         return 0;
  350.                 return 1 + _Size(root->_left) + _Size(root->_right);
  351.         }
  352.         int _Height(Node* root)
  353.         {
  354.                 if (root == nullptr)
  355.                         return 0;
  356.                 return 1 + max(_Height(root->_left), _Height(root->_right));
  357.         }
  358.         void RotateL(Node* parent)
  359.         {
  360.                 Node* subR = parent->_right;
  361.                 Node* subRL = subR->_left;
  362.                 parent->_right = subRL;
  363.                 if (subRL)
  364.                         subRL->_parent = parent;
  365.                 Node* parentParent = parent->_parent;
  366.                 subR->_left = parent;
  367.                 parent->_parent = subR;
  368.                 if (parentParent == nullptr)
  369.                 {
  370.                         _root = subR;
  371.                         subR->_parent = nullptr;
  372.                 }
  373.                 else
  374.                 {
  375.                         if (parent == parentParent->_left)
  376.                         {
  377.                                 parentParent->_left = subR;
  378.                         }
  379.                         else
  380.                         {
  381.                                 parentParent->_right = subR;
  382.                         }
  383.                         subR->_parent = parentParent;
  384.                 }
  385.         }
  386.         void RotateR(Node* parent)
  387.         {
  388.                 Node* subL = parent->_left;
  389.                 Node* subLR = subL->_right;
  390.                 parent->_left = subLR;
  391.                 if (subLR)
  392.                         subLR->_parent = parent;
  393.                 Node* parentParent = parent->_parent;
  394.                 subL->_right = parent;
  395.                 parent->_parent = subL;
  396.                 if (parentParent == nullptr)
  397.                 {
  398.                         _root = subL;
  399.                         subL->_parent = nullptr;
  400.                 }
  401.                 else
  402.                 {
  403.                         if (parent == parentParent->_left)
  404.                         {
  405.                                 parentParent->_left = subL;
  406.                         }
  407.                         else
  408.                         {
  409.                                 parentParent->_right = subL;
  410.                         }
  411.                         subL->_parent = parentParent;
  412.                 }
  413.         }
  414. };
复制代码
10.基于红黑树的map模拟实现

以下是基于红黑树实现的 map 类的代码,此中复用了红黑树的实现。这里的 map 类使用红黑树来存储键值对,并提供插入、删除和查找操作。
  1. template <class Key, class Value>
  2. struct KeyValuePair {
  3.     Key first;
  4.     Value second;
  5.     KeyValuePair(const Key& k = Key(), const Value& v = Value())
  6.         : first(k), second(v) {}
  7.     bool operator<(const KeyValuePair& kv) const {
  8.         return first < kv.first;
  9.     }
  10.     bool operator>(const KeyValuePair& kv) const {
  11.         return first > kv.first;
  12.     }
  13.     bool operator==(const KeyValuePair& kv) const {
  14.         return first == kv.first;
  15.     }
  16. };
  17. template<class Key, class Value, class KeyOfT = KeyValuePair<Key, Value>>
  18. class Map {
  19. private:
  20.     RBTree<KeyValuePair<Key, Value>, KeyValuePair<Key, Value>&, KeyValuePair<Key, Value>*> _tree;
  21. public:
  22.     typedef typename RBTree<KeyValuePair<Key, Value>, KeyValuePair<Key, Value>&, KeyValuePair<Key, Value>*>::Iterator Iterator;
  23.     Map() {}
  24.     pair<Iterator, bool> Insert(const Key& key, const Value& value) {
  25.         return _tree.Insert(KeyValuePair<Key, Value>(key, value));
  26.     }
  27.     bool Erase(const Key& key) {
  28.         return _tree.Delete(KeyValuePair<Key, Value>(key));
  29.     }
  30.     Iterator Find(const Key& key) {
  31.         return _tree.Find(KeyValuePair<Key, Value>(key));
  32.     }
  33.     Value& operator[](const Key& key) {
  34.         Iterator it = Find(key);
  35.         if (it != _tree.End()) {
  36.             return it->second;
  37.         } else {
  38.             auto result = Insert(key, Value());
  39.             return result.first->second;
  40.         }
  41.     }
  42.     Iterator Begin() {
  43.         return _tree.Begin();
  44.     }
  45.     Iterator End() {
  46.         return _tree.End();
  47.     }
  48. };
复制代码
11.结语

红黑树作为一种高效的自均衡二叉查找树,在实际应用中得到了广泛使用。它通过重新着色和旋转操作保持树的均衡,保证了插入、删除和查找操作的时间复杂度为 O(log n)。与 AVL 树相比,红黑树在插入和删除操作中具有更高的服从,非常得当频仍更新的场景。希望通过本文的先容,各人能更好地明白和应用红黑树。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

乌市泽哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表