侯捷 C++ STL标准库和泛型编程 —— 3 容器(关联式容器)

3.3 关联式容器

3.3.0 RB-Tree

红黑树(Red-Black Tree)是一种自平衡的二叉搜索树 BST(AVL 是另一种)

rb-tree 提供遍历操作iterators,按中序遍历遍历,便可以得到排序状态

不能用 iterator 去改变元素的 key(其有严谨的排列规则)

rb-tree 提供两种 insertion 操作:insert_unique()insert_equal(),前者表示 key 独一无二,后者表示 key 可重复

GCC2.9下:

image-20230830083207175
template<class Key, // key的类型class Value, // Value里包含key和dateclass KeyOfValue, // 从Value中取出key的仿函数class Compare, // 比较key大小的仿函数class Alloc = alloc>
class rb_tree
{
protected:typedef __rb_tree_node<Value> rb_tree_node;...
public:typedef rb_tree_node* link_type;...
protected:size_type node_count; // rb-tree节点数量,大小4link_type header; // 头指针,大小4Compare Key_compare; // key比大小的仿函数,大小1// sizeof: 9 ——> 12(填充到4的倍数)...
};

GCC4.9下:

image-20230830093745761

_M_color 是 “枚举”(Enumeration)

3.3.1 set / multiset
测试
image-20230819161037868
void test_multiset(long& value)
{cout << "\ntest_multiset().......... \n";multiset<string> c;  // 创建一个multiset  	char buf[10];		clock_t timeStart = clock();  // 记录起始时间							for(long i=0; i< value; ++i)  // 添加元素到multiset中{try {snprintf(buf, 10, "%d", rand());  // 将随机数转换为字符串格式c.insert(string(buf));  // 将字符串插入multiset中     				}catch(exception& p) {  // 捕获可能的异常cout << "i=" << i << " " << p.what() << endl;  // 输出异常信息abort();  // 终止程序}}cout << "毫秒数 : " << (clock()-timeStart) << endl;  // 输出时间差,计算插入时间	cout << "multiset.size()= " << c.size() << endl;  // 输出multiset大小	cout << "multiset.max_size()= " << c.max_size() << endl;  // 输出multiset的最大容量string target = get_a_target_string();	{timeStart = clock();auto pItem = find(c.begin(), c.end(), target);  // 在multiset中使用 std::find(...) 查找目标字符串cout << "std::find(),毫秒数 : " << (clock()-timeStart) << endl;		...}{timeStart = clock();		auto pItem = c.find(target);  // 在multiset中使用 c.find(...) 查找目标字符串cout << "c.find(),毫秒数 : " << (clock()-timeStart) << endl;		 ...}	c.clear();  // 清空multiset
}

安插元素是使用 insert(),其位置由红黑树决定

容器自己有 c.find(),其会比全局的 ::find()

运行结果:

image-20230819162112550

随机数据填充容器:6609ms(其在填充的时候就进行排序了);直接搜索 ::find():203ms;c.find():0ms


深度探索

以 rb-tree 为底层结构,因此有——元素自动排序,key 与 value 和一

set / multiset 提供遍历操作iterators,按中序遍历遍历,便可以得到排序状态

禁止用 iterator 去改变元素的值(其有严谨的排列规则)

set的key 独一无二,其 insert() 操作用的 rb-tree 的:insert_unique()

multiset 的 key 可以重复,其 insert() 操作用的 rb-tree 的:insert_equal()

GCC2.9下:

// set
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set
{
public:typedef Key key_type;typedef Key value_type;typedef Compare key_compare;typedef Compare value_compare;
private:typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;rep_type t; // 采用红黑树作为底层机制
public:typedef typename rep_type::const_iterator iterator;// 注意:这里是const_iterator,所以不能用iterator改元素...
};
3.3.2 map / multimap
测试
image-20230819162351918
void test_multimap(long& value)
{...multimap<long, string> c;  // 创建一个multimap,key 为 long 类型,value 为 string 类型  	char buf[10];clock_t timeStart = clock();  // 记录起始时间							for(long i=0; i< value; ++i)  // 添加元素到multimap中{try {snprintf(buf, 10, "%d", rand());  // 将随机数转换为字符串格式并复制到缓冲区// multimap 不可使用 [] 做 insertion c.insert(pair<long, string>(i, buf));  // 将元素插入multimap中   						}catch(exception& p) {  // 捕获可能的异常cout << "i=" << i << " " << p.what() << endl;  // 输出异常信息abort();  // 终止程序}}cout << "毫秒数 : " << (clock()-timeStart) << endl;  // 输出时间差,计算插入时间	cout << "multimap.size()= " << c.size() << endl;  // 输出multimap大小cout << "multimap.max_size()= " << c.max_size() << endl;  // 输出multimap的最大容量long target = get_a_target_long();		timeStart = clock();		auto pItem = c.find(target);  // 在multimap中查找目标 key								cout << "c.find(),毫秒数 : " << (clock()-timeStart) << endl;	 if (pItem != c.end())cout << "找到,value=" << (*pItem).second << endl;  // 如果找到,输出找到的值elsecout << "未找到!" << endl;  // 如果未找到,输出未找到的信息	c.clear();  // 清空multimap		  					
}

c.insert(pair<long, string>(i, buf));key 是从1~1000000,value 是随机取的,将其组合为 pair 插入

运行结果:

image-20230819163328911

随机数据填充容器:4812ms(其在填充的时候就进行排序了);c.find():0ms


深度探索

以 rb-tree 为底层结构,因此有——元素自动排序

map/ multimap 提供遍历操作iterators,按中序遍历遍历,便可以得到排序状态

不能用 iterator 去改变元素的key(其有严谨的排列规则),但可以用 iterator 去改变元素的 data

因此 map / multimap 将 user 指定的 key_type 设定成 const

map的key 独一无二,其 insert() 操作用的 rb-tree 的:insert_unique()

multimap 的 key 可以重复,其 insert() 操作用的 rb-tree 的:insert_equal()

GCC2.9下:

template <class Key, // key的类型class T, // data的类型class Compare = less<Key>, class Alloc = alloc>
class map
{
public:typedef Key key_type;typedef T data_type;typedef T mapped_type;typedef pair<const Key, T> value_type;// 注意:这里是const Key ———— 防止改keytypedef Compare key_compare;
private:typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;rep_type t; // 采用红黑树作为底层机制
public:typedef typename rep_type::iterator iterator;...
};

map 的插入元素有特殊写法:c[i] = string(buf),其中 i 就是 key;multimap没有

map 的 [] 功能:

访问元素: 如果指定的键存在于映射中,map[key] 将返回与该键关联的 data;如果键不存在,map[key]自动创建一个新的键值对,key 为指定的 key,data 为默认 data,并返回这个默认 data

3.3.3 HashTable
image-20230830144746686
  • 元素的位置 = key % bucket大小

  • bucket vector 的大小为质数

  • 元素个数大于 bucket 的总数时,bucket vector 扩充并重新打散放在新计算的 bucket 中(rehashing 很花时间)—— bucket 一定比元素多

    在扩充时,按 vector 扩充为2倍大小,但会选择靠进这个数的一个质数做新的大小

GCC2.9下:

template <class Value, // Value里包含key和dateclass Key, // key的类型class HashFcn, // hash函数class ExtractKey, // 从Value中取出key的方法class EqualKey, // 判断key相等的函数class Alloc>
class hashtable
{
public:typedef HashFcn hasher; typedef EqualKey key_equal; // 判断key相等的函数typedef size_t size_type;
private:// 3个函数对象,大小一共3(应该是0,因为一些因素)hasher hash;key_equal equals;ExtractKey get_key;typedef __hashtable_node<Value> node;vector<node*, Alloc> buckets; // vector里3个指针,大小12size_type num_elements; // 大小4// 一共19 ——> 20(调整为4的倍数)
public:size_type bucket_count() const { return buckets.size(); }
};

Hash函数:

偏特化写不同类型的 hash 函数,下图都是数值类型,直接返回就可以

image-20230830153207439

下图对 c 风格的字符串做了处理(也可以自己设计),来生成 hash code

image-20230830153109919

注意:老版本STL没有提供现成的 string 类型的 hash 函数

3.3.4 unordered容器
测试
image-20230818103522538
void test_unordered_multiset(long& value)
{cout << "\ntest_unordered_multiset().......... \n";unordered_multiset<string> c;  // 创建一个 unordered_multiset  	char buf[10];clock_t timeStart = clock();  // 记录起始时间							for(long i=0; i< value; ++i)  // 添加元素到 unordered_multiset 中{try {snprintf(buf, 10, "%d", rand());  // 将随机数转换为字符串格式c.insert(string(buf));  // 将字符串插入 unordered_multiset 中   			  		}catch(exception& p) {  // 捕获可能的异常cout << "i=" << i << " " << p.what() << endl;  // 输出异常信息abort();  // 终止程序}}cout << "毫秒数 : " << (clock()-timeStart) << endl;  // 输出时间差,计算插入时间	cout << "unordered_multiset.size()= " << c.size() << endl;  // 输出 unordered_multiset 大小cout << "unordered_multiset.max_size()= " << c.max_size() << endl;  // 输出 unordered_multiset 的最大容量cout << "unordered_multiset.bucket_count()= " << c.bucket_count() << endl;  // 输出 unordered_multiset 的桶数量cout << "unordered_multiset.load_factor()= " << c.load_factor() << endl;  // 输出 unordered_multiset 的负载因子cout << "unordered_multiset.max_load_factor()= " << c.max_load_factor() << endl;  // 输出 unordered_multiset 的最大负载因子cout << "unordered_multiset.max_bucket_count()= " << c.max_bucket_count() << endl;  // 输出 unordered_multiset 的最大桶数量for (unsigned i=0; i< 20; ++i) {cout << "bucket #" << i << " has " << c.bucket_size(i) << " elements.\n";  // 输出前20个桶中的元素数量}					string target = get_a_target_string();	{timeStart = clock();auto pItem = find(c.begin(), c.end(), target);  // 在 unordered_multiset 中使用 std::find(...) 查找目标字符串cout << "std::find(),毫秒数 : " << (clock()-timeStart) << endl;	if (pItem != c.end())cout << "found, " << *pItem << endl;  // 如果找到,输出找到的元素elsecout << "not found! " << endl;  // 如果未找到,输出未找到的信息	}{timeStart = clock();		auto pItem = c.find(target);  // 在 unordered_multiset 中使用 c.find(...) 查找目标字符串cout << "c.find(),毫秒数 : " << (clock()-timeStart) << endl;	 if (pItem != c.end())cout << "found, " << *pItem << endl;  // 如果找到,输出找到的元素elsecout << "not found! " << endl;  // 如果未找到,输出未找到的信息	}		c.clear();  // 清空unordered_multiset
}					

运行结果:

image-20230819164416021

随机数据填充容器:4406ms;直接搜索 ::find():109ms;c.find():0ms;前二十个 bucket 中只有一个有24个元素

深度探索
image-20230830155954989

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot对MVC、tomcat扩展配置

Springboot在web层的开发基本都是采用Springmvc框架技术&#xff0c;但是Springmvc中的某些配置在boot是没有的&#xff0c;我们就应该根据自己的需求进行对mvc扩展配置 Springboot1.x版本如何配置 通过注解Configuration一个类&#xff0c;继承webmvcconfigureradapter&#…

贪婪的互联网电视让用户忍无可忍,广电总局出手了

广电总局要求电视需要在今年底前实现开机就看电视&#xff0c;开机广告、关机广告将不再被允许&#xff0c;这对于饱受互联网电视无孔不入的广告困扰的消费者来说无疑是一大利好&#xff0c;他们早已无法忍受越来越多的广告。 一、贪婪的互联网电视 互联网电视企业曾以羊毛出在…

华为云云耀云服务器L实例评测 | 实例评测使用之软件性能评测:华为云云耀云服务器下的 Redis 性能评测

华为云云耀云服务器L实例评测 &#xff5c; 实例评测使用之软件性能评测&#xff1a;华为云云耀云服务器下的 Redis 性能评测 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器是什么华为云…

汇编语言——王爽

使用debug执行汇编程序的步骤&#xff1a; dir进入界面 编译&#xff1a;masm 链接&#xff1a;link 执行&#xff1a;debug 文件名 汇编程序格式 assume cs:code cs是寄存器&#xff0c;code是标号&#xff1b; code segment //代码段开始 ... ... mov ax,4…

数据集笔记:华盛顿共享单车OD数据

2010~2022 共享单车OD数据 数据地址&#xff1a;Index of bucket "capitalbikeshare-data"

Linux下C语言操作网卡的几个代码实例?特别实用

前面写了一篇关于网络相关的文章&#xff1a;如何获取当前可用网口。 《简简单单教你如何用C语言列举当前所有网口&#xff01;》 那么如何使用C语言直接操作网口&#xff1f; 比如读写IP地址、读写MAC地址等。 一、原理 主要通过系统用socket()、ioctl()、实现 int sock…

《三国志》游戏的MySQL数据设计与管理

在任何成功的游戏背后,都有一个精心设计和管理的数据系统。这不仅决定了游戏的运行效率,还直接影响到玩家的游戏体验。 本文将深入探讨著名游戏《三国志》中的数据设计和管理。本文将讲解游戏中核心的数据元素、数据管理方法,以及开发团队在数据方面所做的工作。 文章目录 …

Java版本企业工程项目管理系统源码+spring cloud 系统管理+java 系统设置+二次开发

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…

深入理解JavaScript中的事件冒泡与事件捕获

在JavaScript中&#xff0c;事件是交互式网页开发中的关键概念之一。了解事件冒泡和事件捕获是成为一名优秀的前端开发者所必需的技能之一。本文将深入探讨这两个概念&#xff0c;解释它们是如何工作的&#xff0c;以及如何在实际应用中使用它们来处理事件。 一.什么是事件冒泡…

Android Shape设置背景

设置背景时&#xff0c;经常这样 android:background“drawable/xxx” 。如果是纯色图片&#xff0c;可以考虑用 shape 替代。 shape 相比图片&#xff0c;减少资源占用&#xff0c;缩减APK体积。 开始使用。 <?xml version"1.0" encoding"utf-8"?…

智慧安防视频监控技术+AI智能分析算法助力美好乡村建设

上期我们聊到AI智能视频监控技术如何助力美好乡村建设&#xff1f;的相关方案&#xff0c;收到了很多粉丝的讨论与关注&#xff0c;视频监控只是乡村建设极其基础的一环&#xff0c;基于视频监控平台的AI智能算法&#xff0c;将人工智能融合到安防监控之中&#xff0c;才能让乡…

【Linux】详解线程第三篇——线程同步和生产消费者模型

线程同步和生消模型 前言正式开始再次用黄牛抢票来讲解线程同步的思想通过条件变量来实现线程同步条件变量接口介绍初始化和销毁pthread_cond_waitsignal和broadcast 生产消费者模型三种关系用基本工程师思维再次理解基于生产消费者模型的阻塞队列版本一版本二多生多消 利用RAI…

第79步 时间序列建模实战:支持向量机回归建模

基于WIN10的64位系统演示 一、写在前面 这一期&#xff0c;我们介绍支持向量机&#xff08;SVM&#xff09;回归。 同样&#xff0c;这里使用这个数据&#xff1a; 《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemor…

【图像处理】SIFT角点特征提取原理

一、说明 提起在OpenCV中的特征点提取&#xff0c;可以列出Harris&#xff0c;可以使用SIFT算法或SURF算法来检测图像中的角特征点。本篇围绕sift的特征点提取&#xff0c;只是管中窥豹&#xff0c;而更多的特征点算法有&#xff1a; Harris & Stephens / Shi–Tomasi 角点…

C进阶--数据的存储

⚙ 1. 数据类型介绍 1.1基本内置类型 ⭕ 整形&#xff1a; char(char又叫短整型)unsigned charsigned charshortunsigned short[int]signed short [int]intunsigned intsigned intlongunsigned long [int]signed long [int] ⭕ 浮点数&#xff1a; float&#xff08;单精度浮…

Idea引入thymeleaf失败解决方法

报错 Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.Fri Sep 29 09:42:00 CST 2023 There was an unexpected error (typeNot Found, status404). 原因&#xff1a;html没有使用thymeleaf 首先要引入…

java mongodb 并表 group 查询 Bson

对mongodb的使用中&#xff0c;需要将发生额表occr期初表open表&#xff0c;进行union的并表操作后&#xff0c;再进行group&#xff0c;sum&#xff0c;排序&#xff0c;分页操作。 查询了一番后&#xff0c;mongodb4.4版本后&#xff0c;新增了一个管道符&#xff0c;$union…

使用Vue、ElementUI实现登录注册,配置axios全局设置,解决CORS跨域问题

目录 引言 什么是ElementUI&#xff1f; 步骤1&#xff1a;创建Vue组件用于用户登录和注册 1. 基于SPA项目完成登录注册 在SPA项目中添加elementui依赖 在main.js中添加elementui模块 创建用户登录注册组件 配置路由 修改项目端口并启动项目 静态页面展示图 步骤2&#x…

【文献】TOF标定 Time-of-Flight Sensor Calibration for a Color and Depth Camera Pair

文章目录 Article info.Introduction处理TOF误差Take home messagesResourcesIDEAS Article info. Time-of-Flight Sensor Calibration for a Color and Depth Camera Pair IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE, VOL. 37, NO. 7, JULY 2015 Intr…

FreeRTOS入门教程(空闲任务和钩子函数及任务调度算法)

文章目录 前言一、空闲任务概念二、钩子函数概念三、任务调度算法四、任务调度算法实验1.实验代码2.是否抢占3.时间片是否轮转4.空闲任务让步 总结 前言 本篇文章将带大家学习一下什么是空闲任务以及钩子函数&#xff0c;以及学习FreeRTOS中的任务调度算法&#xff0c;了解在F…