C++效率掌握之STL库:unordered_map && unordered_set底层剖析

C++效率掌握之STL库:unordered_map && unordered_set底层剖析

文章目录

看了前面的底层封装后,其实封装的过程及方法都大差不差,unordered_map && unordered_set 也是如此,所以本篇就简单提及一些细节,具体最详细的一些部分可以去看前面的文章

传送门:C++效率掌握之STL库:list底层剖析及迭代器万字详解
传送门:C++效率掌握之STL库:map && set底层剖析及迭代器万字详解

1.unordered_map、unordered_set的基本结构

🚩unordered_set:

template<classK,classV>classunordered_set{structSetKeyOfT{const K&operator()(const K& key){return key;}};public:typedeftypenamehash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;typedeftypenamehash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator const_iterator; const_iterator begin()const{return _ht.begin();} const_iterator end()const{return _ht.end();} pair<const_iterator,bool>insert(const K& key){ pair<typenamehash_bucket::HashTable<K, K, SetKeyOfT>::iterator,bool> ret = _ht.Insert(key);returnpair<const_iterator,bool>(ret.first, ret.second);}private: hash_bucket::HashTable<K, K, SetKeyOfT> _ht;};

🚩unordered_map:

template<classK,classV>classunordered_map{structMapKeyOfT{const K&operator()(const pair<const K, V>& kv){return kv.first;}};public:typedeftypenamehash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::iterator iterator;typedeftypenamehash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator; iterator begin(){return _ht.begin();} iterator end(){return _ht.end();} const_iterator begin()const{return _ht.begin();} const_iterator end()const{return _ht.end();} pair<iterator,bool>insert(const pair<K, V>& kv){return _ht.Insert(kv);} V&operator[](const K& key){ pair<iterator,bool> ret = _ht.Insert(make_pair(key,V()));return ret.first->second;}private: hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> _ht;};

unordered_set 虽然事 k-k 类型,unordered_mapk-v 类型,但是实际上这两个类共用一个哈希表,准确来说是共用同一个模板类型,unordered_set<K,K>unordered_map<K,pair<K,V>>

2.普通迭代器

template<classK,classT,classPtr,classRef,classKeyOfT,classHashFunc>structHTIterator{typedef HashNode<T> Node;typedef HTIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> Iterator; Node* _node;const HashTable<K, T, KeyOfT, HashFunc>* _pht;/*HTIterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pht) :_node(node) ,_pht(pht) {}*/HTIterator(Node* node,const HashTable<K, T, KeyOfT, HashFunc>* pht):_node(node),_pht(pht){}// 普通迭代器时,他是拷贝构造// const迭代器时,他是构造HTIterator(const Iterator& it):_node(it._node),_pht(it._pht){} Ref operator*(){return _node->_data;} Ptr operator->(){return&_node->_data;} Self&operator++(){if(_node->_next){// 当前桶还没完 _node = _node->_next;}else{ KeyOfT kot; HashFunc hf; size_t hashi =hf(kot(_node->_data))% _pht->_table.size();// 从下一个位置查找查找下一个不为空的桶++hashi;while(hashi < _pht->_table.size()){if(_pht->_table[hashi]){ _node = _pht->_table[hashi];return*this;}else{++hashi;}} _node =nullptr;}return*this;}booloperator!=(const Self& s){return _node != s._node;}booloperator==(const Self& s){return _node == s._node;}};

typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> Iterator 和构造函数是为 Insert 操作准备的,因为涉及到普通迭代器创建 const 迭代器

🔥值得注意的是: 有人说不是可以通过权限转化吗?但是权限转化是只有涉及引用和指针的类型时才会生效,而这里是模板参数之间的转化

3.const迭代器

unordered_set 本身无论是 const 迭代器还是普通迭代器都会被 typedefconst_iterator

对于 unordered_map 来说,key 是不允许改变的,value 是可以改变的,但是如果像 set 那样写的话 keyvalue 都不能修改了,所以直接在 pairkeyconst ,控制 value 即可

4.insert返回值 operator[]

🚩unordered_set:

pair<const_iterator,bool>insert(const K& key){//return _ht.Insert(key); pair<typenamehash_bucket::HashTable<K, K, SetKeyOfT>::iterator,bool> ret = _ht.Insert(key);returnpair<const_iterator,bool>(ret.first, ret.second);}

🚩unordered_map:

pair<iterator,bool>insert(const pair<K, V>& kv){return _ht.Insert(kv);} V&operator[](const K& key){ pair<iterator,bool> ret = _ht.Insert(make_pair(key,V()));return ret.first->second;}

这里的转化尤为复杂,一定要看之前文章的详细解析

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述

Read more

C++ 智能指针:示例、原理、适用场景全方位解读

C++ 智能指针:示例、原理、适用场景全方位解读

智能指针被设计出来就是为了解决原生指针的问题的,所以,要理解智能指针的作用,还是得“从问题入手”,看一下原生指针都有哪些“痛点”。理解本文内容需要对虚拟内存的堆和栈对清晰的认识,也需要清楚地知道 C++ 是如何使用堆和栈的,关于这部分内容,请参考 《编程底层概念回顾:虚拟内存、栈、栈帧、堆》和 《C++ 对象和嵌套对象的创建与销毁》两篇文章。 1. 原生指针的“痛” 原生指针也叫裸指针,是 C++ 里知名的“双刃剑”,它的“底层性”和“灵活性”既是优势,也是劣势,在智能指针出现之前,使用指针的过程中会出现很多典型问题,我们逐一梳理一下: * 内存泄漏由裸指针引起的内存泄漏问题真得有很多,究其因在于:C++ 没有像 Java 那样的垃圾回收机制,完全靠程序员掌控堆空间的回收,而人是容易犯错的,可能是忘记了手写 delete 操作,

By Ne0inhk
C++11新特性(下)----《Hello C++ Wrold!》(26)--(C/C++)

C++11新特性(下)----《Hello C++ Wrold!》(26)--(C/C++)

文章目录 * 前言 * lambda表达式 * 可变参数模板 * 展开参数包的方法 * 应用 * 包装器 * fiction包装器 * bind函数 * 作业部分 前言 在 C++11 标准带来的诸多革命性特性中,“简化代码编写” 与 “统一可调用对象管理” 是两大核心目标。lambda 表达式解决了传统仿函数 “定义繁琐、复用性低” 的痛点,让局部场景下的自定义逻辑(如排序规则、回调函数)能以更简洁的匿名函数形式实现;可变参数模板则打破了模板参数数量固定的限制,为 STL 容器(如emplace_back)和通用函数设计提供了灵活的参数处理能力;而 function 包装器与 bind 函数,则进一步整合了函数指针、仿函数、lambda 等不同类型的可调用对象,实现了统一管理与参数适配,甚至让可调用对象存储到容器中成为可能。 这些特性并非孤立存在 ——lambda 的底层依赖仿函数实现,可变参数模板为emplace系列接口提供了技术支撑,

By Ne0inhk
Windows下MATLAB与C/C++混合编程:DLL生成与调用实战

Windows下MATLAB与C/C++混合编程:DLL生成与调用实战

Windows下MATLAB与C/C++混合编程:DLL生成与调用实战 在科学计算与工程开发中,MATLAB凭借其便捷的矩阵运算和可视化能力广受青睐,但面对大规模数据处理或高性能算法时,C/C++的执行效率优势无可替代。将二者结合,通过动态链接库(DLL) 实现混合编程,既能发挥MATLAB的易用性,又能借助C/C++提升核心代码性能。本文将手把手教你在Windows环境下完成从C/C++ DLL编写、编译到MATLAB调用的全流程,附带完整代码与避坑指南! 一、核心原理与准备工作 1. 核心逻辑 C/C++编译生成的DLL文件包含可被外部程序调用的函数,通过__declspec(dllexport)声明导出函数,并使用extern "C"指定C链接规范,避免C++的名称修饰(name mangling)问题,确保MATLAB能正确识别函数名。 MATLAB通过loadlibrary函数加载DLL,解析函数接口后,使用calllib函数调用目标函数,实现数据交互。 2.

By Ne0inhk
【C++ 进阶】继承(上):解锁代码复用的核心密码,体会代码复用的魅力!

【C++ 进阶】继承(上):解锁代码复用的核心密码,体会代码复用的魅力!

前言:C++的三大核心特性是封装、继承和多态。在前文中,我们已经通过类和对象讲解了封装特性。接下来,本文将深入探讨C++继承机制的奥秘。 🌟 专注用图文结合拆解难点+代码落地知识,让技术学习从「难懂」变“一看就会”! 🏠 个人主页 :MSTcheng · ZEEKLOG 💻 代码仓库 :MSTcheng · Gitee📚 精选专栏 :📖 :《C语言》🧩 :《数据结构》💡 :《C++由浅入深》💬 座右铭 :“路虽远行则将至,事虽难做则必成!” 文章目录 * 一、继承的概念及定义 * 1.1继承的概念 * 1.2继承的定义 * 1.3继承方式与访问方式的组合 * 1.4继承类模板 * 二、基类和派生类对象的赋值转换 * 三、继承中的作用域 * 3.1隐藏规则 * 3.2继承作用域的两道笔试题 * 四、总结

By Ne0inhk