【C++ 学习 ㉔】- 详解 map 和 set(下)- map 和 set 的模拟实现

这篇具有很好参考价值的文章主要介绍了【C++ 学习 ㉔】- 详解 map 和 set(下)- map 和 set 的模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、RBT.h

#pragma once
​
#include <utility>
​
namespace yzz
{
    enum Color
    {
        RED,
        BLACK
    };
​
    template<class T>
    struct RBTNode
    {
        RBTNode<T>* _left;
        RBTNode<T>* _right;
        RBTNode<T>* _parent;
        T _data;
        Color _clr;
​
        RBTNode(const T& data = T(), Color clr = RED)
            : _left(nullptr), _right(nullptr), _parent(nullptr)
            , _data(data), _clr(clr)
        { }
    };
​
    template<class T, class Ref, class Ptr>
    struct RBTIterator
    {
        typedef RBTNode<T> Node;
        typedef RBTIterator<T, T&, T*> iterator;
        typedef RBTIterator<T, const T&, const T*> const_iterator;
        typedef RBTIterator<T, Ref, Ptr> self;
​
        Node* _pnode;
​
        RBTIterator(Node* p) : _pnode(p) { }
​
        // 可以通过 iterator 迭代器构造 const_iterator 迭代器
        RBTIterator(const iterator& it) : _pnode(it._pnode) { }
​
        Ref operator*() const
        {
            return _pnode->_data;
        }
​
        T* operator->() const
        {
            return &_pnode->_data;
        }
​
        void increment()
        {
            if (_pnode->_right)
            {
                // 若右子树存在,则找到右子树中值最小的节点(即右子树中最左侧的节点)
                Node* rightMin = _pnode->_right;
                while (rightMin->_left)
                {
                    rightMin = rightMin->_left;
                }
                _pnode = rightMin;
            }
            else
            {
                // 若右子树不存在,表明以 *_pnode 为根的子树已经访问完了
                Node* parent = _pnode->_parent;
                while (parent)
                {
                    if (_pnode == parent->_left)
                    {
                        // 若 *_pnode 是 *parent 的左孩子,
                        // 则下一个该访问的节点就是 *parent
                        break;
                    }
                    else
                    {
                        // 若 *_pnode 是 *parent 的右孩子,
                        // 则以 *parent 为根的子树也已经访问了
                        _pnode = parent;
                        parent = parent->_parent;
                    }
                }
                _pnode = parent;
            }
        }
​
        void decrement()
        {
            if (_pnode->_left)
            {
                // 若左子树存在,则找到左子树中值最大的节点(即左子树中最右侧的节点)
                Node* leftMax = _pnode->_left;
                while (leftMax->_right)
                {
                    leftMax = leftMax->_right;
                }
                _pnode = leftMax;
            }
            else
            {
                Node* parent = _pnode->_parent;
                while (parent)
                {
                    if (_pnode == parent->_right)
                    {
                        // 若 *_pnode 是 *parent 的右孩子,
                        // 则上一个已访问的节点就是 *parent
                        break;
                    }
                    else
                    {
                        // 若 *_pnode 是 *parent 的左孩子
                        _pnode = parent;
                        parent = parent->_parent;
                    }
                }
                _pnode = parent;
            }
        }
​
        self& operator++()
        {
            increment();
            return *this;
        }
​
        self operator++(int)
        {
            self tmp = *this;
            increment();
            return tmp;
        }
​
        self& operator--()
        {
            decrement();
            return *this;
        }
​
        self operator--(int)
        {
            self tmp = *this;
            decrement();
            return tmp;
        }
​
        bool operator==(const self& it) const
        {
            return _pnode == it._pnode;
        }
​
        bool operator!=(const self& it) const
        {
            return _pnode != it._pnode;
        }
    };
​
    template<class K, class T, class KOfT>
    class RBT
    {
        typedef RBTNode<T> Node;
    public:
        /*---------- 构造函数和析构函数 ----------*/
        RBT() : _root(nullptr) { }
​
        ~RBT()
        {
            Destroy(_root);
        }
​
        /*---------- 迭代器 ----------*/
        typedef RBTIterator<T, T&, T*> iterator;
        typedef RBTIterator<T, const T&, const T*> const_iterator;
​
        iterator begin()
        {
            Node* leftMin = _root;
            while (leftMin->_left)
            {
                leftMin = leftMin->_left;
            }
            return iterator(leftMin);
        }
​
        iterator end()
        {
            return iterator(nullptr);
        }
​
        const_iterator begin() const
        {
            Node* leftMin = _root;
            while (leftMin->_left)
            {
                leftMin = leftMin->_left;
            }
            return const_iterator(leftMin);
        }
​
        const_iterator end() const
        {
            return const_iterator(nullptr);
        }
​
        /*---------- 插入 ----------*/
        std::pair<iterator, bool> insert(const T& data)
        {
            if (_root == nullptr)
            {
                _root = new Node(data, BLACK);
                return std::make_pair(iterator(_root), true);
            }
​
            Node* parent = nullptr;
            Node* cur = _root;
            KOfT kot;
            while (cur)
            {
                parent = cur;
                if (kot(data) < kot(cur->_data))
                    cur = cur->_left;
                else if (kot(data) > kot(cur->_data))
                    cur = cur->_right;
                else
                    return std::make_pair(iterator(cur), false);
            }
​
            // 如果插入前树非空,新插入的节点应该是红色节点
            cur = new Node(data, RED);
            Node* tmp = cur;
            if (kot(data) < kot(parent->_data))
                parent->_left = cur;
            else
                parent->_right = cur;
            cur->_parent = parent;
​
            // 出现连续两个红色节点的情形
            while (parent && parent->_clr == RED)
            {
                Node* grandparent = parent->_parent;
                Node* uncle;
                if (grandparent->_left == parent)
                    uncle = grandparent->_right;
                else
                    uncle = grandparent->_left;
​
                // 如果 *uncle 是红色节点
                if (uncle && uncle->_clr == RED)
                {
                    parent->_clr = uncle->_clr = BLACK;
                    grandparent->_clr = RED;
​
                    cur = grandparent;
                    parent = cur->_parent;
                }
                else  // 如果 *uncle 不存在或者是黑色节点
                {
                    if (grandparent->_left == parent && parent->_left == cur)
                    {
                        LL(grandparent);
                        parent->_clr = BLACK;
                        grandparent->_clr = RED;
                    }
                    else if (grandparent->_right == parent && parent->_right == cur)
                    {
                        RR(grandparent);
                        parent->_clr = BLACK;
                        grandparent->_clr = RED;
                    }
                    else if (grandparent->_left == parent && parent->_right == cur)
                    {
                        LR(grandparent);
                        cur->_clr = BLACK;
                        grandparent->_clr = RED;
                    }
                    else if (grandparent->_right == parent && parent->_left == cur)
                    {
                        RL(grandparent);
                        cur->_clr = BLACK;
                        grandparent->_clr = RED;
                    }
                    break;
                }
            }
            _root->_clr = BLACK;
            return std::make_pair(iterator(tmp), true);
        }
        
    private:
        void Destroy(Node*& root)
        {
            // 【注意:root 为 _root 或者某个节点的左或右指针的引用】
            if (root == nullptr)
                return;
​
            Destroy(root->_left);
            Destroy(root->_right);
            delete root;
            root = nullptr;
        }
​
        void LL(Node* parent)
        {
            Node* cur = parent->_left;
            Node* curRight = cur->_right;
​
            parent->_left = curRight;
            if (curRight)
                curRight->_parent = parent;
​
            cur->_right = parent;
            Node* tmp = parent->_parent;
            parent->_parent = cur;
            cur->_parent = tmp;
​
            if (tmp == nullptr)
            {
                _root = cur;
            }
            else
            {
                if (tmp->_left == parent)
                    tmp->_left = cur;
                else
                    tmp->_right = cur;
            }
        }
​
        void RR(Node* parent)
        {
            Node* cur = parent->_right;
            Node* curLeft = cur->_left;
​
            parent->_right = curLeft;
            if (curLeft)
                curLeft->_parent = parent;
​
            cur->_left = parent;
            Node* tmp = parent->_parent;
            parent->_parent = cur;
            cur->_parent = tmp;
​
            if (tmp == nullptr)
            {
                _root = cur;
            }
            else
            {
                if (tmp->_left == parent)
                    tmp->_left = cur;
                else
                    tmp->_right = cur;
            }
        }
​
        void LR(Node* parent)
        {
            Node* cur = parent->_left;
            RR(cur);
            LL(parent);
        }
​
        void RL(Node* parent)
        {
            Node* cur = parent->_right;
            LL(cur);
            RR(parent);
        }
    private:
        Node* _root;
    };
}

二、set.h

#pragma once
​
#include "RBT.h"
​
namespace yzz
{
    template<class K>
    class set
    {
        struct SetKOfT
        {
            const K& operator()(const K& key)
            {
                return key;
            }
        };
        typedef RBT<K, K, SetKOfT> RBT;
    public:
        typedef typename RBT::const_iterator iterator;
        typedef typename RBT::const_iterator const_iterator;
​
        const_iterator begin() const
        {
            return _t.begin();
        }
​
        const_iterator end() const
        {
            return _t.end();
        }
​
        std::pair<const_iterator, bool> insert(const K& key)
        {
            std::pair<typename RBT::iterator, bool> ret = _t.insert(key);
            return std::pair<const_iterator, bool>(ret.first, ret.second);
        }
    private:
        RBT _t;
    };
}

三、map.h

#pragma once
​
#include "RBT.h"
​
namespace yzz
{
    template<class K, class V>
    class map
    {
        struct MapKOfT
        {
            const K& operator()(const std::pair<const K, V>& kv)
            {
                return kv.first;
            }
        };
        typedef RBT<K, std::pair<const K, V>, MapKOfT> RBT;
    public:
        typedef typename RBT::iterator iterator;
        typedef typename RBT::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();
        }
​
        std::pair<iterator, bool> insert(const std::pair<const K, V>& kv)
        {
            return _t.insert(kv);
        }
​
        V& operator[](const K& key)
        {
            std::pair<iterator, bool> ret = _t.insert(std::make_pair(key, V()));
            return ret.first->second;
        }
    private:
        RBT _t;
    };
}

四、test.cpp

#include "set.h"
#include "map.h"
#include <iostream>
using namespace std;
​
void TestSet()
{
    int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    yzz::set<int> s;
    for (const auto& e : arr)
    {
        s.insert(e);
    }
    yzz::set<int>::iterator it = s.begin();
    while (it != s.end())
    {
        // *it = 0;  // error
        cout << *it << " ";
        ++it;
    }
    // 3 7 9 11 14 15 16 18 26
    cout << endl;
}
​
void PrintMap(const yzz::map<int, int>& m)
{
    yzz::map<int, int>::const_iterator it = m.begin();
    while (it != m.end())
    {
        // it->first = 1;  // error
        // it->second = 2;  // error
        cout << it->first << " : " << it->second << endl;
        ++it;
    }
}
​
void TestMap()
{
    int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    yzz::map<int, int> m;
    for (const auto& e : arr)
    {
        m.insert(make_pair(e, e));
    }
    yzz::map<int, int>::iterator it = m.begin();
    while (it != m.end())
    {
        // it->first = 1;  // error
        it->second = 2;  // ok
        cout << it->first << " : " << it->second << endl;
        ++it;
    }
​
    for (const auto& kv : m)
    {
        m[kv.first] = kv.first;
    }
    PrintMap(m);
}
​
int main()
{
    TestSet();
    TestMap();
    return 0;
}

文章来源地址https://www.toymoban.com/news/detail-731129.html

到了这里,关于【C++ 学习 ㉔】- 详解 map 和 set(下)- map 和 set 的模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】 使用红黑树模拟实现STL中的map与set

    前面的文章我们学习了红黑树,也提到了C++STL中的map和set的底层其实就是用的红黑树来实现的(而map和set的使用我们前面也学过了)。 既然红黑树我们也学习过了,那这篇文章我们就用红黑树来简单实现一下STL中的map和set,重点是学习它的框架。 上一篇文章我们实现了红黑

    2024年02月12日
    浏览(30)
  • 【C++练级之路】【Lv.17】【STL】set类和map类的模拟实现

    快乐的流畅:个人主页 个人专栏:《C语言》《数据结构世界》《进击的C++》 远方有一堆篝火,在为久候之人燃烧! STL库中的set类和map类,其底层原理都是 通过红黑树来实现 的。尽管set和map可以各自实现一棵红黑树,但是为了提高代码的复用率,STL库中将红黑树进行了一定

    2024年04月16日
    浏览(38)
  • 【C++】用哈希桶模拟实现unordered_set和unordered_map

    顺序结构中(数组)查找一个元素需要遍历整个数组,时间复杂度为O(N);树形结构中(二叉搜索树)查找一个元素,时间复杂度最多为树的高度次logN。理想的搜索方法: 可以不经过任何比较,一次直接从表中得到要搜索的元素。 构造一种存储结构, 通过某种函数使元素的

    2024年04月11日
    浏览(51)
  • 【C++学习】哈希表的底层实现及其在unordered_set与unordered_map中的封装

    🎉个人名片: 🐼作者简介:一名乐于分享在学习道路上收获的大二在校生 🙈个人主页🎉:GOTXX 🐼个人WeChat:ILXOXVJE 🐼本文由GOTXX原创,首发CSDN🎉🎉🎉 🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路 🐓每日一句:如果没有特别幸运,那就请特

    2024年04月16日
    浏览(46)
  • 【C++进阶】map和set( 万字详解)—— 上篇

    🎇C++学习历程:进阶 博客主页: 一起去看日落吗 持续分享博主的C++学习历程 博主的能力有限,出现错误希望大家不吝赐教 分享给大家一句我很喜欢的话: 也许你现在做的事情,暂时看不到成果,但不要忘记,树🌿成长之前也要扎根,也要在漫长的时光🌞中沉淀养分。静

    2024年01月17日
    浏览(44)
  • 【C++】详解map和set基本接口及使用

    关联式容器也是用来存储数据的,但与序列式容器不同的是,关联式容器里面存储的是 key, value 结构的键值对,因此**在数据检索时比序列式容器效率更高**。 键值对是用来表示 具有一一对应关系的一种结构 ,该结构中一般只包含两个成员变量 – key 和 value;其中 key 代表键

    2024年02月08日
    浏览(43)
  • 【C++ STL之map,set,pair详解】

    在C++的STL(Standard Template Library)中,map是一个非常有用的关联容器。它提供了一种键-值对的数据结构,其中的元素按照键的顺序进行排序,并且每个键是唯一的。本文将详细介绍C++ STL中map的使用方法和一些常见操作。 (1)头文件 (2)初始化方法 可以使用以下方式声明和

    2024年02月12日
    浏览(36)
  • C++【set 和 map 学习及使用】

    ✨个人主页: 北 海 🎉所属专栏: C++修行之路 🎃操作环境: Visual Studio 2019 版本 16.11.17 set 和 map 是 STL 中的容器之一,不同于普通容器,它俩的查找速度极快,常用来存储各种经常被检索的数据,因为这俩容器的底层是平衡二叉搜索树中的红黑树。除此之外,还可以借助其

    2024年02月09日
    浏览(73)
  • 【C++学习】map和set的使用

    🐱作者:一只大喵咪1201 🐱专栏:《C++学习》 🔥格言: 你只管努力,剩下的交给时间! map和set的底层都是二叉搜索树,只是做了更进一步的限制,使其不会出现单只的情况,搜索的时间复杂度保证在O(log 2 N),具体的底层结构后面本喵再详细介绍,现在先来认识以下set和

    2023年04月19日
    浏览(34)
  • 【数据结构】 | java中 map和set 详解

    🎗️ 博客新人,希望大家一起加油进步 🎗️ 乾坤未定,你我皆黑马 我们首先来看一下集合的框架结构: Set实现了Collection接口,Map是一个单独存在的接口。 而下面又分别各有两个类,分别是TreeSet(HashSet)和 HashSet(HashMap) Map和Set的作用是用来查找和搜索的;以后涉及到

    2023年04月10日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包