C++ set&&map的模拟实现

欢迎来到我的频道 【点击跳转专栏】

码云链接 【点此转跳】

文章目录

  • [0. 前言](#0. 前言)
  • [1. set&&map的基本结构](#1. set&&map的基本结构)
  • [2. 迭代器的模拟实现](#2. 迭代器的模拟实现)
  • [3. Insert的实现](#3. Insert的实现)
  • [4. map的【】实现](#4. map的【】实现)
  • 5.完整代码
    • [5.1 <红黑.h>](#5.1 <红黑.h>)
    • [5.2 <set.h>](#5.2 <set.h>)
    • [5.3 <map.h>](#5.3 <map.h>)
    • [5.4 测试样例代码](#5.4 测试样例代码)

0. 前言

学习本章节 必须掌握 红黑树的实现和 set&&map 的基本使用

详情可以参考小编写的
【set的使用】
【map的使用】
【红黑树】

1. set&&map的基本结构

我们利用红黑树对mapset进行封装 首先我们要先根据地层确定他们的结构 setkey 、key的形式,而mapkey、value的形式。

第一个难点就是在红黑树结构中表示出他们不同的形态 第二个点就是为什么要使用<K,K>或者<K,pair<K,V>的形式 第二个问题比较好回答 这里的目的是为了 第一个参数作为索引参数(比如插入,查找操作用的就是第一个参数K),而第二个参数就是类型参数(说人话就是值)。

第一个问题我们可以通过仿函数的形式 通过仿函数返回我们所需要的的值

cpp 复制代码
// 定义节点颜色:红或黑
enum Colour
{
    RED,
    BLACK
};

// 红黑树节点模板定义
template<class T>
struct RBTreeNode
{
    T _data;                    // 节点存储的数据(如 key 或 pair<key, value>)
    RBTreeNode<T>* _left;       // 左子节点指针
    RBTreeNode<T>* _right;      // 右子节点指针
    RBTreeNode<T>* _parent;     // 父节点指针(用于旋转、插入调整和迭代器回溯)
    Colour _col;                // 节点颜色(RED / BLACK)

    // 构造函数:初始化数据,指针置空,颜色默认为 RED(新插入节点通常为红)
    RBTreeNode(const T& data)
        : _data(data)
        , _left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
        // 注意:_col 未在此初始化,但在 Insert 中会显式设为 RED
    {}
};

// 红黑树主类模板
// K: 键类型(用于查找)
// T: 节点存储类型(如 pair<K, V>)
// KeyOfT: 仿函数,用于从 T 中提取 K(如 map 用 first,set 用自身)
template<class K, class T, class KeyOfT>
class RBTree
{
    typedef RBTreeNode<T> Node;
};
cpp 复制代码
    // 模拟 STL 中的 std::set:基于红黑树实现的有序、唯一元素集合
    template<class K>
    class set
    {
    public:
        // 仿函数:用于从 set 的节点数据中提取 key
        // 因为 set 中每个节点只存 key(即 T == K),所以直接返回自身
        struct SetKeyOfT
        {
            // 接收一个 const K&(即节点存储的数据),返回其 key(就是它自己)
            const K& operator()(const K& key)
            {
                return key;
            }
         };
 private:
        // 红黑树成员:
        // - 键类型:K
        // - 节点存储类型:const K(强调 set 中元素不可被修改)
        // - Key 提取器:SetKeyOfT(返回自身)
        RBTree<K, const K, SetKeyOfT> _t;
        };
cpp 复制代码
// 模拟 STL 中的 std::map:基于红黑树实现的有序键值对容器
    // 键(K)唯一,值(V)可修改;整体按键排序
    template<class K, class V>
    class map
    {
    public:
        // 仿函数:用于从 map 节点数据(pair<K, V>)中提取 key
        struct MapKeyOfT
        {
            // 接收一个 pair<K, V> 类型的节点数据,返回其 key(即 .first)
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };
        private:
        // 红黑树成员变量:
        // - 键类型:K
        // - 节点存储类型:pair<const K, V>
        //     → 键为 const,防止用户通过迭代器修改 key(破坏树结构)
        // - Key 提取器:MapKeyOfT(从 pair 中取 .first 作为比较依据)
        RBTree<K, pair<const K, V>, MapKeyOfT> _t;
       }

⚠️:这里要特别注意set 里面 第二个Kmappair<K,V>K必须是const的形式

为了更好的对比 红黑树和map&&set二者的映射关系 小编特地把里面最核心的东西提取出来方便大家进行对比

cpp 复制代码
    template<class K, class V>
    class map
    {
       RBTree<K, const K, SetKeyOfT> _t;
    };

    template<class K>
    class set
{

        RBTree<K, const K, SetKeyOfT> _t;
};

template<class K, class T, class KeyOfT>
class RBTree
{
    typedef RBTreeNode<T> Node;
};

template<class T>
struct RBTreeNode
{
    T _data;                    // 节点存储的数据(如 key 或 pair<key, value>)
    RBTreeNode<T>* _left;       // 左子节点指针
    RBTreeNode<T>* _right;      // 右子节点指针
    RBTreeNode<T>* _parent;     // 父节点指针(用于旋转、插入调整和迭代器回溯)
    Colour _col;                // 节点颜色(RED / BLACK)
};

他们互相的详情映射关系就是这样 这里通过仿函数完美解决了map、set第二个参数不同的问题

2. 迭代器的模拟实现

iterator实现的大框架跟list的iterator思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现,迭代器像指针一样访问的行为。

这一块还是比较基础简单的(毕竟能看到这我相信基础STL的模拟实现起码是十分熟练的)

cpp 复制代码
// 红黑树迭代器:支持中序遍历(左 → 根 → 右),符合 STL 迭代器规范
template<class T, class Ref, class Ptr> 
//Ref 相当于引用
//Ptr 可以相当于指针
struct TreeIterator
{
    typedef RBTreeNode<T> Node;               // 节点类型别名
    typedef TreeIterator<T, Ref, Ptr> Self;   // 当前迭代器类型别名
    Node* _node;                              // 指向当前节点的指针

    // 构造函数:用一个节点指针初始化迭代器(可用于 begin() 或 end())
    TreeIterator(Node* node)
        : _node(node)
    {}

    // 解引用操作符 *it → 返回当前节点数据的引用
    Ref operator*()
    {
        return _node->_data;
    }

    // 成员访问操作符 it-> → 返回当前节点数据的地址(用于访问成员,如 kv.first)
    Ptr operator->()
    {
        return &_node->_data;
    }
    
   // 不等于比较:用于 for 循环或算法中的终止判断(如 it != tree.end())
    bool operator!=(const Self& s) const
    {
        return _node != s._node;
    }
 };   

这里唯一我觉得可能有问题的就是这一段:

cpp 复制代码
// 成员访问操作符 it-> → 返回当前节点数据的地址(用于访问成员,如 kv.first)
    Ptr operator->()
    {
        return &_node->_data;
    }

这涉及到一个知识点 我们假设it为map迭代器 it->second 这其实相当于&(it->_node->data)->second这里是为了美观省略成一个-> 这里大概提一下 具体自己可以搜一下详细资料。


这里的难点是 operator++operator-- 的实现。之前使用部分,我们分析了,map 和 set 的迭代器走的是中序遍历,左子树 -> 根结点 -> 右子树,那么 begin () 会返回中序第一个结点的 iterator 也就是 10 所在结点的迭代器。

迭代器相关内容 具体规则
迭代器遍历方式 中序遍历(左子树→根结点→右子树),begin()返回中序首个结点(如10)
迭代器++(右子树非空) 下一个结点:当前结点右子树的最左结点(右子树的中序首个结点)
迭代器++(右子树为空) 沿祖先路径向上找: 1. 若当前是父亲的左孩子 → 下一个是父亲 2. 若当前是父亲的右孩子 → 继续向上,直到找到"孩子为左的祖先"
⚠️: 我们要抓住 只看重当前节点这一个原则!!


cpp 复制代码
    // 前置自增:++it,将迭代器移动到中序遍历的下一个节点
    Self& operator++()
    {
        // 中序遍历顺序:左子树 → 当前节点 → 右子树
        // 因此,"下一个"节点取决于当前节点是否有右子树

        // 情况1:当前节点有右子树
        // → 中序后继一定是右子树中的最左节点(即右子树的最小值)
        if (_node->_right)
        {
            Node* min = _node->_right;          // 进入右子树
            while (min->_left)                  // 一直向左走到尽头
            {
                min = min->_left;
            }
            _node = min;                        // 更新迭代器指向该最左节点
        }
        // 情况2:当前节点没有右子树
        // → 需要向上回溯,找到第一个"作为左孩子"的祖先节点,
        //   该祖先节点就是中序后继
        else
        {
            Node* cur = _node;                  // 从当前节点开始向上走
            Node* parent = cur->_parent;

            // 循环条件:
            // - parent 存在(未到根以上)
            // - 且当前节点是其父节点的右孩子(说明父节点已在中序中被访问过)
            // 继续向上,直到找到一个祖先,使得当前路径是从其左子树上来
            while (parent && cur == parent->_right)
            {
                cur = parent;                   // 向上移动
                parent = parent->_parent;       // 继续找更高层祖先
            }

            // 循环结束时:
            // - 若 parent != nullptr,则 parent 就是中序后继(cur 是 parent 的左子树中的节点)
            // - 若 parent == nullptr,说明当前节点是整棵树的最右节点,++ 后应为 end()(通常用 nullptr 表示)
            _node = parent;
        }

        // 返回自增后的迭代器引用(符合前置++语义)
        return *this;
    }

这里 -- 因为篇幅原因 就不独立实现了!!


接下来 mapset就只需要调用对应接口就可以了!这里我们可以实现const_iteratoriterator两种形式。
红黑树:

cpp 复制代码
    // 定义普通迭代器:可修改值(但不能改 key,因 T 中 key 为 const)
    typedef TreeIterator<T, T&, T*> Iterator;
    // 定义常量迭代器:不可修改任何内容
    typedef TreeIterator<T, const T&, const T*> Const_Iterator;

    // 返回指向中序第一个元素(最左节点)的迭代器
    Iterator Begin()
    {
        Node* min = _root;
        while (min && min->_left)
        {
            min = min->_left;
        }
        return Iterator(min);
    }

    // 返回 end() 迭代器(通常用 nullptr 表示"末尾之后")
    Iterator End()
    {
        return Iterator(nullptr);
    }

    // const 版本的 Begin()
    Const_Iterator Begin() const
    {
        Node* min = _root;
        while (min && min->_left)
        {
            min = min->_left;
        }
        return Const_Iterator(min); 
    }

    // const 版本的 End()
    Const_Iterator End() const
    {
        return Const_Iterator(nullptr); 
    }

map&&set

cpp 复制代码
// 定义迭代器类型
        // 注意:set 中所有元素都是 const(不可修改),因此底层红黑树存储的是 const K
        typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;

        // 在标准库中,set 的普通迭代器应具有 const 行为(即不能通过迭代器修改 key)
        // 此处将 const_iterator 也定义为同一种类型(实际更严谨的做法是区分,但常见简化处理)
        typedef typename RBTree<K, const K, SetKeyOfT>::Iterator const_iterator;

        // 返回指向第一个元素的迭代器(中序最左节点)
        iterator begin()
        {
            return _t.Begin();
        }

        // 返回 end() 迭代器(通常对应 nullptr)
        iterator end()
        {
            return _t.End();
        }

        // const 版本的 begin()
        const_iterator begin() const
        {
            return _t.Begin();
        }

        // const 版本的 end()
        const_iterator end() const
        {
            return _t.End();
        }

-----------------------------------------------------------------------------------
// 定义迭代器类型:使用红黑树中已定义的 Iterator
        // 节点存储类型为 pair<const K, V>:
        //   - key 为 const:防止用户通过迭代器修改 key(破坏树结构)
        //   - value 为 V:允许通过 it->second 修改 value
        typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;

        // 定义常量迭代器类型:只读访问
        typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Const_Iterator const_iterator;

        // 非 const 版本 begin():返回指向最左节点(最小 key)的迭代器
        iterator begin()
        {
            return _t.Begin();
        }

        // 非 const 版本 end():返回"末尾之后"的迭代器(通常为 nullptr 封装)
        iterator end()
        {
            return _t.End();
        }

        // const 版本 begin():用于 const map 对象,返回 const_iterator
        const_iterator begin() const
        {
            return _t.Begin();  // 调用红黑树的 const Begin()
        }

        // const 版本 end()
        const_iterator end() const
        {
            return _t.End();    // 调用红黑树的 const End()
        }

这里还有个易错的注意点:
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Const_Iterator const_iterator;

很多人会不小心写成 typedef typename RBTree<K, pair<const K, const V>, MapKeyOfT>::Const_Iterator const_iterator 这么写会造成模版参数不匹配的问题 RBTree 的模版参数是 RBTree<K,pair<const K,V>,MapKeyOfT>_t;
还有个易忘点:
typename 是 C++ 模板编程中的一个关键字,主要用于在依赖于模板参数的上下文中,告诉编译器某个名字是一个类型名(type name),而不是变量、函数或其他东西。

场景 是否需要 typename
vector<T>::iterator ✅ 需要(依赖于 T
MyClass::NestedTypeMyClass 不依赖模板参数) ❌ 不需要
T::value_typeT 是模板参数) ✅ 需要
函数返回类型(C++11 之前) ✅ 需要 (C++14+ 在 auto 推导中可省略)

3. Insert的实现

这里insetr 功能的实现 我们只需要修改 红黑树里面的insert 就可以了

其实这里面实际需要修改的东西并不多 只需要将返回值进行修改然后对里面一些参数进行微调(利用仿函数 针对map&&set两种不同情况)

cpp 复制代码
pair<iterator,bool> Insert(const T& data)
  • T:红黑树中存储的实际数据类型(如 pair)。
  • 返回值:
    • Iterator:指向插入节点(或已存在节点)的迭代器。
    • bool:true 表示成功插入,false 表示 key 已存在(未插入)。

然后就是再补上仿函数和修改一下返回值信息即可

为邻方便大家比较,截取了一部分:

修改前:

修改后:

完整代码:

cpp 复制代码
 // 插入函数:返回 {迭代器, 是否插入成功}
    pair<Iterator, bool> Insert(const T& data)
    {
        // 情况1:空树 → 直接创建根节点,并设为黑色(红黑树性质:根必须为黑)
        if (_root == nullptr)
        {
            _root = new Node(data);
            _root->_col = BLACK;
            return { Iterator(_root), true };
        }

        // 创建 Key 提取器(用于比较)
        KeyOfT kot;
        Node* parent = nullptr;
        Node* cur = _root;

        // 查找插入位置(类似 BST 插入)
        while (cur)
        {
            if (kot(cur->_data) < kot(data))
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (kot(cur->_data) > kot(data))
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                // key 已存在 → 插入失败,返回已存在节点的迭代器
                return { Iterator(cur), false };
            }
        }

        // 创建新节点(默认红色)
        cur = new Node(data);
        Node* newnode = cur;
        cur->_col = RED;
        cur->_parent = parent;

        // 将新节点链接到父节点
        if (kot(parent->_data) < kot(data))
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }

        // ===== 红黑树插入后调整(核心:修复可能违反的红黑性质)=====
        // 红黑树性质要求:
        // 1. 节点是红或黑
        // 2. 根是黑
        // 3. 红节点的孩子必须是黑(不能有两个连续红节点)
        // 4. 从任一节点到其所有叶子的路径包含相同数量的黑节点(黑高一致)

        // 调整循环:只要父节点存在且为红色(违反性质3),就需要处理
        while (parent && parent->_col == RED)
        {
            Node* grandfather = parent->_parent; // 祖父节点(必存在,因为 parent 是红 → 不可能是根)

            // 情况A:父亲是祖父的左孩子
            if (grandfather->_left == parent)
            {
                Node* uncle = grandfather->_right; // 叔叔节点(祖父的右孩子)

                // 子情况A1:叔叔存在且为红色 → 变色(父、叔变黑,祖父变红),继续向上处理
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = BLACK;
                    uncle->_col = BLACK;
                    grandfather->_col = RED;

                    // 继续以祖父为"当前节点"向上检查
                    cur = grandfather;
                    parent = cur->_parent;
                }
                // 子情况A2:叔叔不存在或为黑色 → 需要旋转 + 变色
                else
                {
                    // 子子情况A2a:当前节点是父节点的左孩子 → 右单旋(LL 型)
                    if (cur == parent->_left)
                    {
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    // 子子情况A2b:当前节点是父节点的右孩子 → 左右双旋(LR 型)
                    else
                    {
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break; // 调整后满足性质,退出循环
                }
            }
            // 情况B:父亲是祖父的右孩子(对称处理)
            else // grandfather->_right == parent
            {
                Node* uncle = grandfather->_left; // 叔叔节点(祖父的左孩子)

                if (uncle && uncle->_col == RED)
                {
                    parent->_col = BLACK;
                    uncle->_col = BLACK;
                    grandfather->_col = RED;

                    cur = grandfather;
                    parent = cur->_parent;
                }
                else
                {
                    // 子子情况B2a:当前节点是父节点的右孩子 → 左单旋(RR 型)
                    if (cur == parent->_right)
                    {
                        RotateL(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    // 子子情况B2b:当前节点是父节点的左孩子 → 右左双旋(RL 型)
                    else
                    {
                        RotateR(parent);
                        RotateL(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
            }
        }

        // 无论是否进入循环,最后都确保根为黑色(性质2)
        _root->_col = BLACK;

        return { Iterator(newnode), true };
    }

4. map的【】实现

这设计到STL里面map的[]的底层原理 具体原理请参考我写的map的使用 【点击转跳】

cpp 复制代码
// operator[]:支持"插入或访问"语义
// - 若 key 存在:返回对应 value 的引用
// - 若 key 不存在:插入 {key, V()}(默认构造值),并返回该 value 的引用
V& operator[](const K& key)
{
    // 尝试插入一个 pair,包含 key 和 V 类型的默认构造值
    // 调用 insert 方法,它会尝试将 {key, V()} 插入到红黑树中
    // 返回值是一个 pair<iterator, bool>:
    //   - iterator 指向插入点或已存在的元素
    //   - bool 表示是否成功插入新节点 (true 表示插入成功,false 表示 key 已存在)
    pair<iterator, bool> ret = insert({ key, V() });

    // 解析返回的 pair:
    // - 如果 ret.second == true,说明是新插入的节点
    // - 如果 ret.second == false,说明 key 已存在,指向的是现有节点

    // ret.first 是一个迭代器,指向了包含所需 key 的节点
    // 对于 map 中存储的数据类型 pair<const K, V>,通过 ->second 可以访问和修改 value 部分
    // 注意:即使 key 已存在,这里也直接返回了对应的 value 引用,允许后续修改
    return ret.first->second;
}

5.完整代码

5.1 <红黑.h>

cpp 复制代码
//
//  红黑.h
//  红黑树
//
//  Created by Fanz on 2025/12/30.
//

#pragma once
// 枚举值表示颜色
using namespace std;
enum Colour
{
    RED,
    BLACK
};

template<class T>
struct RBTreeNode
{
    // 这里更新控制平衡也要加入parent指针
    T _data;
    RBTreeNode<T>* _left;
    RBTreeNode<T>* _right;
    RBTreeNode<T>* _parent;
    Colour _col;
    RBTreeNode(const T& data)
        :_data(data)
        , _left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
    {}
};
template<class T,class Ref,class Ptr>
struct TreeIterator
{
    typedef RBTreeNode<T> Node;
    typedef TreeIterator<T,Ref,Ptr> Self;
    Node* _node;
    

    TreeIterator(Node* node)
        :_node(node)
    {}

    Ref operator*()
    {
        return  _node->_data;
    }
    
    Ptr operator->()
    {
        return &_node->_data;
    }
    
   bool operator != (const Self& s) const
    {
        return _node!=s._node;
    }
    // 前置自增:++it,将迭代器移动到中序遍历的下一个节点
    Self& operator++()
    {
        // 中序遍历顺序:左子树 → 当前节点 → 右子树
        // 因此,"下一个"节点取决于当前节点是否有右子树

        // 情况1:当前节点有右子树
        // → 中序后继一定是右子树中的最左节点(即右子树的最小值)
        if (_node->_right)
        {
            Node* min = _node->_right;          // 进入右子树
            while (min->_left)                  // 一直向左走到尽头
            {
                min = min->_left;
            }
            _node = min;                        // 更新迭代器指向该最左节点
        }
        // 情况2:当前节点没有右子树
        // → 需要向上回溯,找到第一个"作为左孩子"的祖先节点,
        //   该祖先节点就是中序后继
        else
        {
            Node* cur = _node;                  // 从当前节点开始向上走
            Node* parent = cur->_parent;

            // 循环条件:
            // - parent 存在(未到根以上)
            // - 且当前节点是其父节点的右孩子(说明父节点已在中序中被访问过)
            // 继续向上,直到找到一个祖先,使得当前路径是从其左子树上来
            while (parent && cur == parent->_right)
            {
                cur = parent;                   // 向上移动
                parent = parent->_parent;       // 继续找更高层祖先
            }

            // 循环结束时:
            // - 若 parent != nullptr,则 parent 就是中序后继(cur 是 parent 的左子树中的节点)
            // - 若 parent == nullptr,说明当前节点是整棵树的最右节点,++ 后应为 end()(通常用 nullptr 表示)
            _node = parent;
        }

        // 返回自增后的迭代器引用(符合前置++语义)
        return *this;
    }
};


template<class K, class T, class KeyOfT>
class RBTree
{
    typedef RBTreeNode<T> Node;
public:
    typedef TreeIterator<T,T&,T*> Iterator;
    typedef TreeIterator<T,const T&,const T*> Const_Iterator;

    
    Iterator Begin()
    {
        Node* min= _root;
        while (min&&min->_left)
        {
            min=min->_left;
        }
        
        return Iterator(min);
    }
    
    Iterator End()
    {
        return Iterator(nullptr);
    }

    Const_Iterator Begin() const
    {
        Node* min= _root;
        while (min&&min->_left)
        {
            min=min->_left;
        }
        
        return Const_Iterator(min);
    }
    
    Const_Iterator End() const
    {
        return Const_Iterator(nullptr);
    }

    
    pair<Iterator, bool> Insert(const T& data)
    {
        
        if (_root == nullptr)
        {
            _root = new Node(data);
            _root->_col = BLACK;
            
            return {Iterator(_root),true};
        }
        
        KeyOfT kot;
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (kot(cur->_data) < kot(data))
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (kot(cur->_data) > kot(data))
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return {Iterator(cur),false};
            }
        }
        
        cur = new Node(data);
        Node* newnode=cur;
        cur->_col = RED;
        
        if (kot(parent->_data) < kot(data))
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }
        
        cur->_parent = parent;
        
        while (parent&&parent->_col==RED)
        {
            Node* grandfather = parent->_parent;
            if (grandfather->_left==parent) //父亲在左
            {
                Node* uncle = grandfather->_right;
                //叔叔存在且为红 变色即可
                if (uncle&&uncle->_col==RED)
                {
                    parent->_col = BLACK;
                    uncle->_col = BLACK;
                    grandfather->_col=RED;
                    
                    //继续往上处理
                    cur = grandfather;
                    parent =cur->_parent;
                }
                else //叔叔不存在,或者叔叔存在且为黑
                {
                    //     g
                    //  p     u
                    //c
                    //右单旋
                    if(cur==parent->_left)//如果cur等于父亲的左边
                    {
                        RotateR(grandfather);
                        parent->_col=BLACK;
                        grandfather->_col=RED;
                    }
                    else
                    {
                        //   g
                        //p     u
                        //  c
                        //左右双旋
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col=BLACK;
                        grandfather->_col=RED;
                    }
                    break;
                }
            }
            else //父亲在右 grandfather->_right == parent
            {
                Node* uncle = grandfather->_left;
                //叔叔存在且为红 变色即可
                if (uncle&&uncle->_col==RED)
                {
                    parent->_col = BLACK;
                    uncle->_col = BLACK;
                    grandfather->_col=RED;
                    
                    //继续往上处理
                    cur = grandfather;
                    parent =cur->_parent;
                }
                else //叔叔不存在,或者叔叔存在且为黑
                {
                    //     g
                    //  u     p
                    //          c
                    //左单旋
                    if(cur==parent->_right)//如果cur等于父亲的左边
                    {
                        RotateL(grandfather);
                        parent->_col=BLACK;
                        grandfather->_col=RED;
                    }
                    else
                    {
                        //   g
                        //u     p
                        //    c
                        //左右双旋
                        RotateR(parent);
                        RotateL(grandfather);
                        cur->_col=BLACK;
                        grandfather->_col=RED;
                    }
                    break;
                }
            }
        }
        //最简单处理根的方式 循环结束后不做判断 直接把根变成黑的
        _root->_col=BLACK;
        return {Iterator(newnode),true};
        
        }
        
    
            
private:
    
    
    Node* _root = nullptr;
    //copy的AVL树代码
    void RotateR(Node* parent)
    {
        //结合图1 看代码 不然脑子一团浆糊
        Node* subL =parent->_left;
        Node* subLR =subL->_right;
        
        parent->_left = subLR;
        //注意 subLR可能为空
        if(subLR)
        subLR->_parent=parent;
        
        //如果调整的是局部子树 所以最好纪录下parent的parent
        Node* parentParent = parent->_parent;
        
        subL->_right=parent;
        parent->_parent=subL;
        
        //如果parent是根节点
        if (parent == _root)
        {
            _root=subL;
            subL->_parent=nullptr;
        }
        else
        {
          //  如果调整的是局部子树
            if(parentParent->_left==parent)
            {
                parentParent->_left=subL;
            }
            else
            {
                parentParent->_right=subL;
            }
            
            subL->_parent=parentParent;
        }
        
    }
    
    void RotateL(Node* parent)
    {
        Node* subR=parent->_right;
        Node* subRL=subR->_left;
        
        parent->_right=subRL;
        //防止subRL为空
        if (subRL)
            subRL->_parent=parent;
        
        Node* parentParent=parent->_parent;
        
        subR->_left=parent;
        parent->_parent=subR;
        
        if (parent==_root)
        {
            _root=subR;
            subR->_parent=nullptr;

        }
        else
        {
          //  如果调整的是局部子树
            if(parentParent->_left==parent)
            {
                parentParent->_left=subR;
            }
            else
            {
                parentParent->_right=subR;
            }
            
            subR->_parent=parentParent;
        }
        
    }
      
};

5.2 <set.h>

cpp 复制代码
//
//  set.h
//  map和set封装
//
//  Created by Fanz on 2026/1/3.
//
#pragma once
#include"红黑.h"

namespace fcy
{
   template<class K>
   class set
{
    struct SetKeyOfT
    {
        const K& operator()(const K& key)
        {
            return key;
        }
    };
public:
      typedef typename RBTree<K,const  K, SetKeyOfT>::Iterator iterator;
    typedef typename RBTree<K,const  K, SetKeyOfT>::Iterator const_iterator;
        iterator begin()
        {
            return _t.Begin();
        }

        iterator end()
        {
            return _t.End();
        }
    const_iterator begin() const
    {
        return _t.Begin();
    }

    const_iterator end() const
    {
        return _t.End();
    }

    pair<iterator, bool> insert(const K& k)
    {
        return _t.Insert(k);
    }

private:
    RBTree<K,const K,SetKeyOfT> _t; //第二个模版参数决定存什么
};

}

5.3 <map.h>

cpp 复制代码
//
//  map.h
//  map和set封装
//
//  Created by Fanz on 2026/1/3.
//
#pragma once
#include"红黑.h"

namespace fcy
{
   template<class K,class V>
   class map
{
    struct MapKeyOfT
    {
        const K& operator()(const pair<K,V>& kv)
        {
            return kv.first;
        }
    };
public:
    typedef typename RBTree<K,pair<const K,V>, MapKeyOfT>::Iterator iterator;
    typedef typename RBTree<K,pair<const K,V>, MapKeyOfT>::Const_Iterator const_iterator;

        iterator begin()
        {
            return _t.Begin();
        }

        iterator end()
        {
            return _t.End();
        }
    const_iterator begin() const
    {
        return _t.Begin();
    }

    const_iterator end() const
    {
        return _t.End();
    }
    pair<iterator, bool> insert(const pair<K,V>& kv)
    {
        return _t.Insert(kv);
    }
    V& operator[](const K& key)
    {
        pair<iterator,bool> ret = insert({key,V()});
        return ret.first->second;
    }
private:
    RBTree<K,pair<const K,V>,MapKeyOfT>_t;
};

}

5.4 测试样例代码

cpp 复制代码
//
//  main.cpp
//  map和set封装
//
//  Created by Fanz on 2026/1/3.
//
#include <iostream>
#include <utility>
#include "map.h"
#include "set.h"
using namespace std;
void test_set()
{
    fcy::set<int> s;
    s.insert(4);
    s.insert(1);
    s.insert(2);
    s.insert(12);
    s.insert(22);
    s.insert(2223);
    s.insert(-2);
    s.insert(0);

    fcy::set<int>::iterator it = s.begin();
    while (it != s.end())
    {
        // *it = 1;

        cout << *it << " ";
        ++it;
    }
    cout << endl;
}
void test_map()
{
    fcy::map<string, string> dict;
    dict.insert({ "sort", "排序" });
    dict.insert({ "left", "左边" });
    dict.insert({ "right", "右边" });

    dict["left"] = "左边,剩余"; // 修改
    dict["insert"] = "插入";  // 插入+修改
    dict["string"];          // 插入

    fcy::map<string, string>::iterator it = dict.begin();
    while (it != dict.end())
    {
        // 不能修改first,可以修改second
        //it->first += 'x';
        //it->second += 'x';
        cout << it->first << ":" << it->second << endl;
        ++it;
    }
    cout << endl;
}

int main()
{
    test_set();
    test_map();

    return 0;
}
相关推荐
你怎么知道我是队长1 天前
C语言---枚举变量
c语言·开发语言
李慕婉学姐1 天前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
吃茄子的猫1 天前
quecpython中&的具体含义和使用场景
开发语言·python
云栖梦泽1 天前
易语言中小微企业Windows桌面端IoT监控与控制
开发语言
数据大魔方1 天前
【期货量化实战】日内动量策略:顺势而为的短线交易法(Python源码)
开发语言·数据库·python·mysql·算法·github·程序员创富
fpcc1 天前
C++编程实践——链式调用的实践
c++
Edward.W1 天前
Python uv:新一代Python包管理工具,彻底改变开发体验
开发语言·python·uv
小熊officer1 天前
Python字符串
开发语言·数据库·python
月疯1 天前
各种信号的模拟(ECG信号、质谱图、EEG信号),方便U-net训练
开发语言·python