《STL源码剖析》学习笔记-第5章 关联式容器(二)
来源:互联网 发布:最好的建筑设计软件 编辑:程序博客网 时间:2024/04/30 00:50
1、set和multiset
set的特性:
(1)所有元素都会根据元素的键值自动被排序。
(2)set是集合,它的元素的键值就是实值,实值就是键值,不允许两个元素有相同的值。
(3)不可以通过set的iterator来改变元素的值,因为set的元素值就是键值,改变键值会违反元素排列的规则。
(4)在客户端对set进行插入或删除操作后,之前的迭代器依然有效。当然,被删除的元素的迭代器是个例外。
(5)它的底层机制是RB-tree。几乎所有的操作都只是转调用RB-tree的操作行为而已。
multiset和set几乎一样,唯一的区别是,multiset允许键值重复。因此set使用底层RB-tree的insert_unique()
实现插入,而multiset插入采用的是RB-tree的insert_equal()
而非insert_unique()
。
测试实例:
#include <set>#include <iostream>using namespace std;int main(){ int ia[5] = {0,1,2,3,4}; int n = sizeof(ia)/sizeof(ia[0]); cout<<n<<endl;// 5 set<int> iset(ia, ia+n); cout<<"size="<<iset.size() << endl;// size=5 cout<<iset.count(3)<<endl;// 1 iset.insert(3);//插入无效,元素不允许重复 cout<<"size="<<iset.size() << endl;// size=5 cout<<iset.count(3)<<endl;// 2 iset.erase(1); cout<<iset.count(1)<<endl;// 0 set<int>::iterator ite1=iset.begin(); set<int>::iterator ite2=iset.end(); for(; ite1 != ite2; ++ite1) cout<<*ite1<<" "; cout<<endl;//0 2 3 4 //关联式容器,应采用其所提供的find函数搜寻元素,会比使用 //STL算法find()更优效率!因STL find()只是循序搜寻。 ite1 = iset.find(3);//使用自身提供的find函数 if(ite1 != iset.end()) cout<<"3 found!"<<endl; else cout<<"3 not found!"<<endl; //企图通过迭代器改变set元素,是不被允许的 //*ite1 = 9;//error ! return 0;}
2、map和multimap
map的特性:
(1)所有元素都会根据元素的键值自动被排序。
(2)map的所有元素都是pair,第一个值是键值,第二个是实值。
(3)map不允许两个元素拥有相同的键值。
(4)可以通过map的迭代器来改变元素的实值,但不可以改变键值,那样会违反元素的排列规则。
(5)在客户端对map进行插入或删除操作后,之前的迭代器依然有效。当然,被删除的元素的迭代器是个例外。
(6)它的底层机制是RB-tree。几乎所有的操作都只是转调用RB-tree的操作行为而已。
multimap和map几乎一样,唯一的区别是,multimap允许键值重复。因此map使用底层RB-tree的insert_unique()
实现插入,而multimap插入采用的是RB-tree的insert_equal()
而非insert_unique()
。
3、hashtable
1、hashtable概述
hashtable可以提供对任意有名项的存取和删除操作,这种结构的用意在于提供常数时间的的基本操作,而不依赖于插入元素的随机性,是以统计为基础的。
散列函数(hash function):负责将某一元素映射为一个”大小可接受之索引”。简而言之,就是将大数映射为小数。
使用hash function带来的问题:可能有不同元素映射到相同的位置(相同索引)。这便是碰撞或冲突问题。解决碰撞问题的方法:线性探测(linear probing),二次探测(quadratic probing),开链(separate chaining)
等。stl hashtable采用的hash方式是开链法。
(1)线性探测:当hash function计算出某个元素的插入位置,而该位置空间不再可用时,怎么做?最简单的办法就是循序往下一一寻找,知道找到一个可用空间为止。
需要两个假设:a.表格足够大。b.每个元素都能够独立。
线性探测会造成主集团(primary clustering)问题:平均插入成本的成长幅度,远高于负载系数的成长幅度。
(2)二次探测:主要用来解决主集团问题。解决碰撞的方程式为F(i) = i^2
。如果hash function计算出新元素的位置为H,而该位置实际上已被使用,那么就依次尝试H+1^2,H+2^2,H+3^2,H+4^2,....,H+i^2
,而不像线性探测尝试的是H+1,H+2,H+3,H+4,....,H+i
。
二次探测可以消除主集团,却可能造成次集团(secondary clustering):两个元素经hash function计算出来的位置若相同,则插入时所探测的位置也相同,形成某种浪费。消除次集团的方法如复式散列。
(3)开链:这种做法是在每一个表格元素中维护一个list。hash function为我们分配某一个list,然后我们在哪个list身上执行元素的插入、搜寻、删除等操作。若list够短,速度还是够快。
使用开链法,表格的负载系数将大于1。SGI STL hashtable便采用的是开链法。
2、hashtable结构
hashtable表格内的每个单元,涵盖的不只是个节点(元素),而可能是一桶节点,因此称为bucket。
SGI STL中hash table使用的是开链法进行的冲突处理,其结构如图所示:
bucket所维护的linked list不采用STL的list或者slist,而是自行维护hash table node。而至于buckets聚合体,则使用vector来完成,以便有动态扩容能力。
STL中的hash迭代器,是一种forward迭代器,只能+。有指向当前节点的指针和指向对应的vector的指针,没有后退操作,也就是没有所谓的逆向迭代器。
hashtable以质数来设计表格大小,预先计算好了28个质数,以备随时访问,大约都是两倍的关系递增,同时提供一个函数,查询28个质数中,“最接近某数且大于某数”的质数作为vector的长度,如果需要重新分配,则分配下一个质数长度的vector。
stl hash table扩张表格的触发条件是:当元素的数目大于或等于表格的大小。(这个条件应该是为了保证常数操作时间,在统计基础上得出的)。
insert分为insert_unique
和insert_equal
操作,前者保证插入的数不能有重复,后者可以插入键值相同的数。可以先用unique之后再用equal。insert_unique:
先调用resize函数,看是否需要增大vector,然后插入,vector的索引通过取余得到。resize:如果已有元素的个数大于vector的size,需要根据得到的最新质数,分配新的空间,将在旧空间的元素,重新计算hash,复制到新的空间,最后旧空间与新空间swap一下即可。insert_equal:
也是先调用resize,遍历找到和他相同的节点,在该节点的前面插入。
hashtable有一些无法处理的型别,比如string,double,float。除非用户为那些型别写了相应的hash function。
4、hash_set,hash_map,hash_multiset,hash_multimap
这些容器和前面介绍的一一对应,只不过这些都是以hash_tabel为底层实现机制的。
底层机制决定了这两组容器的区别:
RB-tree组对元素实现排序,而hashtable组没有;
RB-tree组的查找时间复杂度为lg(n),而hashtable组为常数时间;
RB-tree组在空间利用上,不会浪费结点,而hashtable组可能会有一些空置桶。 hash_multiset
和hash_multimap
插入使用的是inset_equal。其它操作与multiset和multimap相同。
- 《STL源码剖析》学习笔记-第5章 关联式容器(二)
- 《STL源码剖析》学习笔记-第5章 关联式容器
- 《STL源码剖析》学习笔记-第4章 序列式容器(二)
- STL源码剖析 - 第5章 关联式容器 - set
- STL源码剖析 - 第5章 关联式容器 - map
- STL源码剖析 - 第5章 关联式容器 - multiset
- STL源码剖析 - 第5章 关联式容器 - multimap
- STL源码剖析 - 第5章 关联式容器 - hashtable
- STL源码剖析 - 第5章 关联式容器 - hash_set
- STL源码剖析 - 第5章 关联式容器 - hash_map
- STL源码剖析 - 第5章 关联式容器 - hash_multiset
- STL源码剖析 - 第5章 关联式容器 - hash_multimap
- STL源码剖析: 第5章 关联式容器
- STL源码剖析 - 第5章 关联式容器 - RB-tree(红黑树)
- STL源码剖析笔记-5关联式容器
- 《STL源码剖析》学习笔记系列之五——关联式容器(2)
- 《STL源码剖析》学习笔记系列之五——关联式容器(1)
- STL学习笔记之容器--vector(二)源码剖析
- JSON与fastjson
- JavaScript中this的理解
- 【BestCoder Round #81 (div.2)】HDU5670Machine
- (二)认识标签(1)
- 算法1.1.15/16/18/19题
- 《STL源码剖析》学习笔记-第5章 关联式容器(二)
- 上机题目(初级)-大数求和
- 聊聊Socket、TCP/IP、HTTP、FTP及网络编程
- Androidstuido快捷键
- 玩转Android之加速度传感器的使用,模仿微信摇一摇
- Linux安装Java
- c++上机实验5-项目三
- Flask 数据库高级多对多关系
- java 单例模式(Singleton)