C++ unordered_map

1. unordered系列关联式容器

在C++98 中, STL 提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到  \log_{2}N ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11 中, STL 又提供了 4 个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同,该系列容器使用哈希表进行封装。

2. unordered_map的介绍

1. unordered_map 是存储 <key, value> 键值对的关联式容器,其允许通过 key 快速的索引到与其对应的value
2. unordered_map 中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
3. 在内部 ,unordered_map 没有对 <kye, value> 按照任何特定的顺序排序 , 为了能在常数范围内找到key 所对应的 value unordered_map 将相同哈希值的键值对放在相同的桶中。
4. unordered_map 容器通过 key 访问单个元素要比 map 快,但它通常在遍历元素子集的范围迭代方面效率较低。
5. unordered_maps 实现了直接访问操作符 (operator[ ]) ,它允许使用 key 作为参数直接访问value。
6. 它的迭代器至少是前向迭代器。

3. unordered_map的使用

1. unordered_map的构造

函数声明功能介绍
unordered_map()
构造不同格式的 unordered_map 对象

2. unordered_map的容量

函数声明
功能介绍
bool empty() const
检测 unordered_map 是否为空
size_t size() const
获取 unordered_map 的有效元素个数

3. unordered_map的迭代器

函数声明 功能介绍
iterator  begin()
返回 unordered_map 第一个元素的迭代器
iterator end()
返回 unordered_map 最后一个元素下一个位置的迭代器
const_iterator cbegin() const
返回 unordered_map 第一个元素的 const 迭代器
const_iterator cend() const
返回 unordered_map 最后一个元素下一个位置的 const 迭代器

4. unordered_map的元素访问

函数声明功能介绍
mapped_type& operator[ ] (const key_type& k)
返回与 key 对应的 value ,没有返回一个默认值
注意:该函数中实际调用哈希桶的插入操作,用参数 key V() 构造一个默认值往底层哈希桶中插入,如果key 不在哈希桶中,插入成功,返回 V() ,插入失败,说明 key 已经在哈希桶中,将key 对应的 value 返回。

5. unordered_map的查询

函数声明功能介绍
iterator find(const K& key)
返回 key 在哈希桶中的位置
size_t count(const K& key)
返回哈希桶中关键码为 key 的键值对的个数
注意: unordered_map key 是不能重复的,因此 count 函数的返回值最大为 1

6. unordered_map的修改操作

函数声明
功能介绍
pair<iterator,bool> insert (const value_type& x )
向容器中插入键值对

size_type erase ( const key_type& x )

删除容器中的键值对
void clear()
清空容器中有效元素个数
void swap(unordered_map&)
交换两个容器中的元

7. unordered_map的桶操作

函数声明
功能介绍
size_t bucket_count()const
返回哈希桶中桶的总个数
size_t bucket_size(size_t n)const
返回 n 号桶中有效元素的总个数
size_t bucket(const K& key)
返回元素 key 所在的桶号

4.unordered_map的模拟实现

首先我们要使用哈希表进行封装unordered_map即可,如下是HashTable.cpp的文件,有关哈希表的详细介绍,可以点击了解C++哈希表。

#include <iostream>
#include <vector>
using namespace std;
namespace OpenHash
{template<class T>struct HashNode{T _data;HashNode* _next;HashNode(const T& data):_data(data), _next(nullptr){}};//将key转换为整型方便取模template <class K>struct Hash{size_t operator()(const K& key){return key;}};//模板特化,将string类型转换为整型template<>class Hash<string>{size_t operator()(const string& s){size_t ret = 0;for (auto e : s){ret = ret * 31 + e;}return ret;}};//实现迭代器//因为迭代器的实现需要借助HashTable,所以需要前置定义template <class K, class T, class KeyOfT, class HashFunc = Hash<K>>class HashTable;template <class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc = Hash<K>>struct HashTableIterator{typedef typename HashNode<T> Node;typedef typename HashTableIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;typedef typename HashTable<K, T, KeyOfT, HashFunc> HashTable;HashTable* _ht;Node* _node;HashTableIterator() = default;HashTableIterator(const Node*& node, const HashTable*& ht):_ht(ht), _node(node){}Self& operator++(){//遍历当前桶if (_node->_next)_node = _node->_next;//找下一个桶else{KeyOfT kot;HashFunc hf;//获取索引值size_t index = hf(kot(_node->_data)) % _ht->_table.size();++index;while (index < _ht->_table.size() && _ht->_table[index] == nullptr)++index;if (index == _ht->_table.size())_node = nullptr;else_node = _ht->_table[index];}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const Self& s){return _node == s._node;}bool operator!=(const Self& s){return _node != s._node;}};template <class K, class T, class KeyOfT, class HashFunc>class HashTable{public://友元(因为iterator需要用到_table)template <class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>friend struct HashTableIterator;typedef typename HashNode<T> Node;typedef typename HashTableIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;//构造函数HashTable():_table(vector<Node*>()), _n(0){}iterator begin(){for (size_t i = 0; i < _table.size(); i++){if (_table[i])return iterator(_table[i], this);}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}iterator find(const K& key){if (_table.size() == 0){return iterator(nullptr, this);}KeyOfT kot;HashFunc hf;size_t index = hf(key) % _table.size();Node* cur = _table[index];while (cur){if (kot(cur->_data) == key)return iterator(cur, this);cur = cur->_next;}return iterator(nullptr, this);}pair<iterator, bool> insert(const K& key){//第一次插入需要扩容if (_table.size() == 0)_table.resize(10);//不能出现重复数据if (find(key) != iterator(nullptr, this)){return make_pair(find(key), false);}KeyOfT kot;HashFunc hf;//桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,//可能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对//哈希表进行增容,那该条件怎么确认呢?开散列最好的情况是:每个哈希桶中刚好挂一个//节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数//时,可以给哈希表增容。//负载因子到1,需要扩容if (_n == _table.size()){vector<Node*> newtable;newtable.resize(_table.size() * 2);//重新映射到新表for (auto e : _table){Node* cur = e;while (cur){size_t index = hf(kot(cur->_data)) % newtable.size();cur->_next = newtable[index];newtable[index] = cur;cur = cur->_next;}}}size_t index = hf(key) % _table.size();Node*& cur = _table[index];while (cur)cur = cur->_next;cur = new Node(key);return make_pair(iterator(cur, this), true);}bool erase(const K& key){KeyOfT kot;HashFunc hf;size_t index = hf(key) % _table.size();Node* cur = _table[index], * pre = _table[index];while (cur){if (kot(cur->_data) == key){//要删除该位置第一个元素if (cur == pre)_table[index] = cur->_next;elsepre->_next = cur->_next;delete cur;_n--;return true;}pre = cur;cur = cur->_next;}return false;}private:vector<Node*> _table;size_t _n;//有效数据个数};
}

unordered_map.cpp文件如下

#include"HashTable.cpp"
namespace lbk
{template<class K,class Hash=OpenHash::Hash<K>>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename OpenHash::HashTable<K,K,SetKeyOfT,Hash>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}iterator find(const K& key){return _ht.find(key);}pair<iterator, bool> insert(const K& key){return _ht.insert(key);}bool erase(const K& key){return _ht.erase(key);}private:OpenHash::HashTable<K, K, SetKeyOfT, Hash> _ht;};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3270186.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

我在百科荣创企业实践——简易函数信号发生器(6)

对于高职教师来说,必不可少的一个任务就是参加企业实践。这个暑假,本人也没闲着,报名参加了上海市电子信息类教师企业实践。7月8日到13日,有幸来到美丽的泉城济南,远离了上海的酷暑,走进了百科荣创科技发展有限公司。在这短短的一周时间里,我结合自己的教学经验和企业的…

Leetcode 剑指 Offer II 088.使用最小花费爬楼梯

题目难度: 简单 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 数组的每个下标作为一个阶梯&#xff0c;第 i 个阶梯对应着一个非…

5 Java的基本程序设计结构(基本语法4)- 集合之ArryList 和什么是包装类?

文章目录 前言一、集合二、基本数据类型的包装类三、ArryList1 ArryList对象的创建2 ArryList常见成员方法(1)boolean add(E e) : 添加元素,返回值表示是否添加成功(2)void add(int index, E e) :在指定索引位置插入元素。(3)boolean remove(E e) : 删除第一个指定元素…

从json到protobuf,接口效率的提升

在express开发的前后端调用中&#xff0c;express作为接收方是不二之选&#xff0c;它有一些很好用的body解析器来解析传入数据&#xff1b;而作为请求发起方&#xff0c;axios是非常方便的&#xff0c;这是一个很好的选择&#xff0c;它可以传输多种类型的数据给接收方。 通常…

Tekion 选择 ClickHouse Cloud 提升应用性能和指标监控

本文字数&#xff1a;4187&#xff1b;估计阅读时间&#xff1a;11 分钟 作者&#xff1a;ClickHouse team 本文在公众号【ClickHouseInc】首发 Tekion 由前 Tesla CIO Jay Vijayan 于 2016 年创立&#xff0c;利用大数据、人工智能和物联网等技术&#xff0c;为其汽车客户解决…

Week 3 DAY 6

Product C - Product (atcoder.jp) 一共N层&#xff0c;对于每一层的每个数&#xff0c;都遍历上一层更新过后的结果&#xff0c;更新为新的结果&#xff0c; 比如样例&#xff1a; 2 40 3 1 8 4 2 10 5动态数组a表示储存上一层除后留下来的数&#xff0c; 第一次a数组中只…

关于开源项目分享的通知

后续会逐步分享更多好用的开源项目&#xff0c;加入圈子&#xff1a; 圈子加入https://pc.fenchuan8.com/#/index?forum86631&yqm5EV39扫码加入&#xff1a;

初识git工具~~上传代码到gitee仓库的方法

目录 1.背景~~其安装 2.gitee介绍 2.1新建仓库 2.2进行相关配置 3.拉取仓库 4.服务器操作 4.1克隆操作 4.2查看本地仓库 4.3代码拖到本地仓库 4.4关于git三板斧介绍 4.4.1add操作 4.4.2commit操作 4.4.3push操作 5.一些其他说明 5.1.ignore说明 5.2git log命令 …

日拱一卒 | JVM

文章目录 什么是JVM&#xff1f;JVM的组成JVM的大致工作流程JVM的内存模型 什么是JVM&#xff1f; 我们知道Java面试&#xff0c;只要你的简历上写了了解JVM&#xff0c;那么你就必然会被问到以下问题&#xff1a; 什么是JVM&#xff1f;简单说一下JVM的内存模型&#xff1f;…

电脑系统安装软件,让系统安装变得更简单。

电脑原版操作系统下载&#xff1a;MSDN系统库 电脑U盘装机pe系统&#xff1a;优启通或微PE工具 驱动安装&#xff1a;360 驱动大师 电脑装机常用软件下载&#xff1a;https://www.bgrdh.com/favorites/7875.html

do while打印1~10

#include<stdio.h> int main() {int i 1;do{printf("%d", i);i;} while (i < 10);return 0; }

【JUC】LockSupport线程等待唤醒

文章目录 LockSupport线程等待唤醒机制三种让线程等待和唤醒的方法Object类中的wait和notify方法实现线程等待和唤醒Condition接口中的await和signal方法实现线程的等待和唤醒上述两种方法使用限制条件LockSupport类中的park等待和unpark唤醒LockSupport 是什么主要方法代码测试…

网易云音乐黑胶VIP会员免费领取入口直达词令是什么?

网易云音乐黑胶VIP会员免费领取是指网易云音乐VIP会员根据不同的等级尊享不同的权益&#xff0c;其中赠送礼品卡就是其一。不同等级的网易云音乐VIP会员可赠送的7天黑胶VIP会员张数不同&#xff0c;但是由于数量有限&#xff0c;每次更新后先领先得&#xff0c;我们将不定期根据…

SpringBoot3:轻松使用Jasypt实现配置文件信息加密

文章目录 前言一、概述1.1 Jasypt库简介1.2 Jasypt库的主要特点 二、开发环境三、Jasypt集成到SpringBoot33.1 引入依赖3.2 配置Jasypt3.3 加密配置文件信息3.3.1 方案一&#xff08;不推荐&#xff09;a.编写测试类生成加密后的配置文件信息b.运行c.修改原本的配置文件信息 3.…

vue实现电子签名、图片合成、及预览功能

业务功能&#xff1a;电子签名、图片合成、及预览功能 业务背景&#xff1a;需求说想要实现一个电子签名&#xff0c;然后需要提供一个预览的功能&#xff0c;可以查看签完名之后的完整效果。 需求探讨&#xff1a;后端大佬跟我说&#xff0c;文档我返回给你一个PDF的oss链接…

开源大模型的格式转成GGUF,并量化后使用ollama推理

https://github.com/ggerganov/llama.cpphttps://github.com/ggerganov/llama.cpp使用到的工具: llama.cpp ollama 步骤 1、下载llama.cpp,并使用make编译 2、新建conda环境,安装llama.cpp里所需的库(requirements.txt) 3、下载需要量化的模型

1. BES2700ZP概述

1. 概述 恒玄BES2700采用RTX5操作系统&#xff0c;配合mindmics算法或者自研算法。 RTX5相关接口可参考&#xff1a;RTX v5 Implementation 2. 芯片框架 2.1 内存 - 4MB 2.2 flash - 8MB

openmv 学习笔记(24电赛笔记)

模版匹配 模版匹配是一种计算机视觉技术&#xff0c;用于图像或者视频中查找特定的模版或者对象&#xff0c;查找模版可以是数字或者是物体&#xff0c;技术通过在目标图像中寻找与模版图像相似的区域来实现匹配。这种技术最早起源在 20世纪70年代 的图像处理领域。 使用模版匹…

《python程序语言设计》第6章14题 估算派值 类似莱布尼茨函数。但是我看不明白

这个题提供的公式我没看明白&#xff0c;后来在网上找到了莱布尼茨函数 c 0 for i in range(1, 902, 100):a (-1) ** (i 1)b 2 * i - 1c a / bprint(i, round(4 / c, 3))结果 #按题里的信息&#xff0c;但是结果不对&#xff0c;莱布尼茨函数到底怎么算呀。

无人机的飞行模式

无人机的飞行模式是提升飞行效率和完成特定任务的关键。现代无人机通常配备多种智能飞行模式&#xff0c;这些模式能够帮助飞行员高效且安全地完成飞行任务。以下是几种常见的无人机飞行模式及其应用场景的解析&#xff1a; 一、跟随模式 应用场景&#xff1a;跟随模式非常适…