c++11の关联容器

摘要:
关联的容器(如map和set)共享大多数顺序容器的操作。关联容器不提供front和push_ front、pop_ front和back、push_ back和pop_ back操作。map的下标操作与vector的下标操作相同:返回与键关联的值。例如,记录每个单词的出现次数:mapword_count;字符串;//统计单词_单词在count中出现的次数,而++单词_ count;映射容器的插入使用类型对的参数。此函数返回一个pair类型的对象,包括指向具有e.first键的元素的映射迭代器,以及一个bool类型的对象(指示插入是否成功)。

一、关联容器

C++的容器类型可以分为顺序容器和关联容器两大类。对于关联容器,主要有map和set,对于这两种,根据不同的维度,衍生出了8种容器

map                                      //值对

set                                         //仅有值

multimap                               //允许关键字重复的值对

multiset                                 //允许重复的值

unordermap                          //无序值对

unorderset                             //无序值

unordermultimap                   //无序值对,允许关键字重复

unordermultiset                      //无序值,允许重复

二、pair类型

  在开始介绍关联容器之前,我们需要了解一种与之相关的标准库类型——pair类型,该类型定义在头文件utilty中。下表是pair类型提供的操作

pair<T1,T2>    p1;                     创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化
pair<T1,T2>    p1(v1,v2);              创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v2,second成员初始化为v2。
make_pair(v1,v2)                       以v1,v2值创建一个新的pair对象,其元素类型分别是v1,v2类型
p1<p2                                  两个pair对象之间的小于运算,遵循字典顺序
p1==p2                                 如果两个pair对象的first和second值依次相等,则它们相等
p.first                                返回p中名为first的数据成员
p.second                               返回p中名为second的数据成员

和容器一样,pair也是一种模板类型。它的数据成员是公有的,分别命名为first和second,只需点操作就可以访问其成员。其定义初始化的操作也很简单,除了构造函数外,pair还提供了一个make_pair函数来创建pair对象,并赋值给已存在的pair对象。

pair<string,string>    next_auth;
string    first,last;
while(cin>>first>>last)
    next_auth=make_pair(first,last);
等价于
next_auth=pair<string,string>(first,last);

三、map类型

 map是键-值对的集合。map类型可以理解为关联数组:可以使用键作为下标来获取一个值,正如内置数组类型一样。map和set等关联容器共享大部分顺序容器的操作。关联容器不提供front、push_front、pop_front、back、push_back和pop_back操作。

1.map对象的定义

  在使用map对象之前,需要在头文件中包含map头。其定义示例如下:

#include<map>
map<string,int>  word_count;    

  此外,map还共有3种构造函数用于定义和初始化。

map<k,v>    m;                 创建一个名为m的空map对象,其键和值类型分别为k和v类型
map<k,v>    m(m2);             创建一个m2的副本m,m和m2必须要有相同的键和值类型
map<k,v>    m(b,e);            创建map类型的对象m,存储迭代器b和e标记范围内所有元素的副本。元素的类型必须能转换位pair<const k,v>

  

2.map定义的类型

  由于map对象的元素是键-值对,即每个元素包含两个部分:键以及由键关联的值。vaule_type是存储元素的键以及值得pair类型,而且键位const。下表为map类定义的类型。

map<K,V>::key_type               在map容器中,用作索引的键的类型
map<K,V>::mapped_type            在map容器中,键所关联的值的类型
map<K,V>::value_type             一个pair类型。它的first元素具有const map<K,V>::key_type 类型,而second元素具有map<K,V>::mapped_type类型

  注意对map迭代器进行解引用将产生的是pair类型的对象,它的first成员存放的是键,为const,second成员存放的是值。

3.map中添加元素

  给map添加元素有两种方式:一是使用insert成员实现。二是先用下标获取元素,让然后给获取的元素赋值。

  map使用下标和vector类似,返回的都是下标关联的值,但是map的下标是键而不是递增的数字。下面的程序很好的说明了这个特点。

map<string,int>    word_count;
word_count["Anna"]=1;

  首先在word_count中查找键为Anna的元素,没有找到。接着将一个新的键-值对插入到word_count容器中,键为Anna,值初始化为0;最后会把值1赋值给键为Anna的元素。我们可以看到,用下标访问map中不存在的元素,会导致在map容器中添加一个新元素,它的键即为该下标值。map的下标运算和vector下标运算相同:返回键相关联的值。运用map容器的这些特点,可以使编程编的很简练。如下面记录每个单词出现次数的例子:

map<string,int>    word_count;
string    word;
//统计word_count中某个单词出现的次数
while(cin>>word)
    ++word_count;

  map容器的insert使用的是pair类型的参数。如下表为map容器提供的insert操作。

  

m.insert(e)              e是一个用在m上的vaule_type类型的值。如果键e.first不在m中,则插入一个键为e.first值为e.seconde的元素。如果该键在m中已存在。则m保持不变。
                         该函数返回一个pair类型的对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入成功。
m.insert(beg,end)        beg和end是标记元素范围的迭代器,其中的元素必须为m.value_type类型的键-值对。
                         对于该范围内的素有元素,如果它的键在m中不存在,则将该键及其关联的值插入m。返回void    
m.insert(iter,e)         e是一个用在vaule_type类型的值。如果键不在m中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置。
                         返回一个迭代器,指向m中具有给定键的元素。

  如下:

复制代码
//方法一
word_count.insert(map<string,int>::value_type("Anna",1));

//方法二,使用make_pair
word_count.inser(make_pair("Anna",1));

//方法三,使用typedef
typedef  map<string,int>::value_type  valType;
word_count.insert(valType("Anna",1));
复制代码

4.map中元素的查找与读取

  map中下标读取元素的缺点是当不存在该元素时会自动添加,有时这是我们不希望看到的。所以map提供了另外两个操作:count和find,用于检查某个键是否存在而不会插入该键。

m.count(k)               返回m中k出现次数
m.find(k)                如果m容器中存在按k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器

  count成员的返回值只能是0或1,因为map值允许一个键对应一个实例。如果返回值为非0,则可以用下标操作来获取该键所关联的值。

int occurs=0;
if(word_count.count("foobar"))
    occurs=word_count["foobar"];

  find操作凡湖指向元素的迭代器,如果元素不存在,则返回end迭代器。

int  occurs=0;
map<string,int>::iterator  it=word_count.find("foobar");
if(it!=word_count.end())
    occurs=it->second;

5.map中删除元素

  从map容器中删除元素用erase操作,它有三种变化形式,如下:

m.erase(k)                删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数
m.srase(p)                从m中删除迭代器p指向的元素。p必须指向m中确实存在的元素,而且不能等于m.end()。返回void型
m.erase(b,e)              从m中删除一段范围内的元素,该范围由迭代器对b和e标记。b和e必须标记m中的一段有效范围:即b和e都必须指向m中的元素或最后元素的下一个位置
                          而且,b要么在e的钱main,要么和e相等。返回void

6.map对象的迭代遍历

  map和其他容器一样也提供begin和end运算。

复制代码
map<string,int>::const_iterator   map_it=word_count.begin();

while(map_it!=word_count.end()){
    cout<<map_it->first<<"occurs"
            <<map_it->second<<"time"<<endl;
     ++map_it;
}
复制代码

四、set类型

  set只是单纯的键的集合。当只想知道一个值是否存在时,使用set容器是最合适的。set容器支持大多数map的操作,包括构造函数、insert、count、find、erase操作。但是不包括下标操作,没有定义mapped_type类型。在set容器中value_type不是pair类型,而是与key_type相同的类型。与map一样,set容器中存储的键也是唯一的。

1.set的定义与使用

  使用set之前必须包含set头文件,set支持的操作基本与map提供的相同。

复制代码
vector<int > ivec;
for(vector<int>::size_type  i=0;i!=10;++i){
    ivec.push_back(i);
    ivec.push_back(i);
}

//用ivec初始化set
set<int>  iset(ivec.begin(),ivec.end());
cout<<ivec.size()<<endl;        //输出20
cout<<iset.size()<<end;         //输出10
    
复制代码

2.在set中添加元素 

复制代码
//方法一,直接插入
set<string>  set1;
set1.insert("the");    

//方法二,使用迭代器
set<string>  set2;
set2.insert(ivec.begin(),ivec.end());
复制代码

3.从set中获取元素

  set没有下标操作,为了通过键从set中获取元素,可使用find运算。如果仅是判断某个元素是否存在,也可使用count操作,返回值只能是1或0。

五、无序容器

无序容器是通过哈希函数来构建的,通过哈希函数映射到桶,无序容器的质量取决于哈希函数的质量和桶的质量与数量

桶接口

c.bucket_count()          //正在使用的桶的数量

c.max_bucket_count()  //最多能容纳多少个桶

c.bucket_size()             //第n个桶中有多少个元素

c.bucket(k)                    //k在那个桶

桶迭代

local-iterator                    //  可用来访问桶中元素的迭代器类型

const_local_iterator        // const版本

c.begin(n)    c.end(n)      //桶n的首尾元素迭代器

c.cbegin(n) c.cend(n)      //

哈希策略

c.load_factor()              //每个桶的平均元素数量,返回float

c.max_load_factor()      //维护桶

c.rehash()                      //重新哈希

c.reserve()                     //

免责声明:文章转载自《c++11の关联容器》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇python 简单图像识别--验证码《名门暗战》下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

接口返回值结果转换成JSON

接口返回值结果转换成JSON,具体的方法如下: public static String GetJsonValue(String result,intindex,String key){ intindexloc,indexkey; String newstr; indexloc=result.indexOf(...

【C#写日志两个简单方法】

方法一:以日期为日志文件名. public void WriteLog(stringmsg) { string filePath = AppDomain.CurrentDomain.BaseDirectory + "Log"; if (!Directory.Exists(filePath)) {...

Postgresql数据库的一些字符串操作函数(转)

今天做项目遇到客户反映了一个麻烦的事情,有一些数据存在,但就是在程序中搜索不出来,后来分析,发现问题为数据前面有几个空白字符,后来用SQL 查询了一下,发现八九个数据表中,数千万条数据中有将近三百万条数据存在相同的问题,本想着在查询时添加匹配符'%',后来试运行了一下,发现不可行,因 为尚有很多其它页面存在类似的搜索问题,并且这样会极大地影响到查询的速度,...

unity 在移动平台中,文件操作路径详解

今天,这篇文章其实是个老生常谈的问题咯,在网上类似的文章也比比皆是,在此我只是做个详细总结方便大家能够更好、更快的掌握,当然,如有不足的地方 欢迎指正!!!相信大家在开发过程中,难免会保存一些文件在客户端进行本地化操作。如:配置文件,状态文件,Assetbundle文件等等...最近总有人问我:1.保存了一个xml在客户端,能读取里面的数据,可是不能修改,...

PostgreSQL 字符串操作函数 迎客

函数:string || string 说明:String concatenation 字符串连接操作例子:'Post' || 'greSQL' = PostgreSQL 函数:string || non-string or non-string || string说明:String concatenation with one non-string i...

使用replaceAll实现字符串替换

使用replaceAll实现字符串替换,具体要求为将字符串“abc123bcd45ef6g7890”中的数字替换成汉字“数字”,如果是连续的数字那么替换为一个汉字“数字”。 在Java api中的String类提供了replaceAll方法,实现将字符串中匹配正则表达式的字符串替换成其它字符串,replaceAll方法的声明如下所示: String rep...