C++容器-3关联容器map、set

C++容器-3关联容器map、set


关联容器与顺序容器的本质区别在于:关联容器是通过键(key)存储和读取元素的,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。 

关联容器支持通过键来高效地查找和读取元素,两个基本的关联容器是map和set。map的元素是“键-值”对的二元组形式:键用作元素在map中的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。set和map类型的对象所包含的元素都具有不同的键。如果需要一个键对应多个实例,则需要使用multimap或multiset类型。这两种类型允许多个元素拥有相同的键。

map           关联数组:元素通过键来存储和读取 

set             大小可变的集合,支持通过键实现的快速读取 

multimap   支持同一个键多次出现的map类型 

multiset      支持同一个键多次出现的set类型

pair类型

为了讲map,得先将pair类型:pair就是一个两个类型的组合,比如一个人的学号就可以是pair<int,string>,其中的int是学号,string是名字。

    pair模板类用来绑定两个对象为一个新的对象,该类型在<utility>头文件中定义。pair类型提供的操作如下表:

pair<T1, T2> p1; 创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化

pair<T1, T2> p1(v1, v2); 创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2

make_pair(v1, v2) 以v1和v2值创建一个新的pair对象,其元素类型分别是v1和v2的类型

p1 < p2 字典次序:如果p1.first<p2.first或者!(p2.first < p1.first)&& p1.second<p2.second,则返回true

p1 == p2 如果两个pair对象的first和second成员依次相等,则这两个对象相等。

p.first 返回p中名为first的(公有)数据成员

p.second 返回p中名为second的(公有)数据成员


一、Map

map就是一个容器,里面装的就是若干个pair。每个pair的第一个元素,称为键(注意键的类型必须支持小于(<)操作!),第二个元素,称为值。对于普通的map,每个键都对应一个值。这样的看起来,键类似于数组的下标,而值类似于数组的值。map类定义了3种类型,分别为key_type、mapped_type、以及vaule_type。他们分别表示了键的类型、值的类型,以及一个pair类型,pair的第一个元素是键,第二个元素是值。

1、添加元素

首先讲讲如何给imap添加元素:有两种的方法,使用(下标)或者使用insert

 

map和set容器中,元素是有序存储的(升序).

 

使用下标这种方法与vector等类型的容器相矛盾。如果是一个空的vector,则不能使用下标直接访问,必须pusn_back进元素才行,直接访问会报错。而对于map如果没有这个键(下标),则会自动的向map中添加这个键,值为0。下标操作的返回值,就是这个键关联的值。利用这个性质,我们可以很方便的完成统计的功能,举个例子:

#include <iostream>
using namespace std;

int main()  
{  
    string str;  
    map<string,int> wordCount;  
    while(cin>>str)  
    {  
        ++wordCount[str];  
    }  
      
    map<string,int>::iterator it_map = wordCount.begin();  
    cout<<"word"<<"\t\t"<<"count"<<endl;  
    for(;it_map != wordCount.end();++it_map)  
        cout<<it_map->first<<"\t\t"<<it_map->second<<endl;  
    return 0;  
  
}  

使用时如果键不存在,则赋值为0,然后对其自增。即变成了1。

insert方法有多个重载函数,表明你插入的是一个pair,还是一对迭代器指明的若干个pair,还是插入一个pair到指定的位置,但通常使用的插入一个pair,这个函数最关键是它的返回值。这个返回值也是一个pair,pair的第一个元素是指向该map类型的迭代器,另一个是bool类型的变量,表明插入成功与否。可以用insert重写上面的程序:

 
 
int main()  
{  
    string str;  
    map<string,int> wordCount;  
    while(cin>>str)  
    {  
        //对于每个单词,都尝试去插入它  
        pair<map<string,int>::iterator,bool>ret = wordCount.insert(make_pair(str,1));  
        //通过检测返回值来判断插入是否成功  
        if(!ret.second)  
            //插入失败表明map中有这个单词,只需要把对应键的值自增即可  
            ++ret.first->second;  
    }  
    map<string,int>::iterator it_map = wordCount.begin();  
    cout<<"word"<<"\t\t"<<"count"<<endl;  
    for(;it_map != wordCount.end();++it_map)  
        cout<<it_map->first<<"\t\t"<<it_map->second<<endl;  
    return 0;  
}  

那么如何读取map的元素呢?虽然我们也可以使用键来读取,但是潜在的问题是如果该键不存在,就会自动创建,这个特点并不是我们所希望的。我们可以通过count或者find函数来查找某个键是否存在。这两个函数的区别在于count返回的是出现的次数(对于map只能为0或者1),而find则返回的是指向该键的迭代器(如果没有找到,返回超末端迭代器:.end())。这意味着如果你是为为了统计是否存在,使用count就可以了,如果你找到某个元素并且还想使用它,那么find会比较合适

删除元素使用使用erase操作,这与顺序容器差别不大。但是要注意的是,关联容器的顺序是按照“键”排列的

 

下面通过一个小程序来说明:

#include <iostream>  
#include <map>  
#include <string>  
#include <vector>  
using namespace std;  
  
int main()  
{  
    string str;  
    map<string,int> wordCount;  
    while(cin>>str)  
    {  
        //对于每个单词,都尝试去插入它  
        pair<map<string,int>::iterator,bool>ret = wordCount.insert(make_pair(str,1));  
        //通过检测返回值来判断插入是否成功  
        if(!ret.second)  
            //插入失败表明map中有这个单词,只需要把对应键的值自增即可  
            ++ret.first->second;  
    }  
      
  
    map<string,int>::iterator it_map = wordCount.begin();  
    cout<<"word"<<"\t\t"<<"count"<<endl;  
    for(;it_map != wordCount.end();++it_map)  
        cout<<it_map->first<<"\t\t"<<it_map->second<<endl;  
  
    //count方法:对于map,返回1或者0  
    int cnt = 0;  
    cnt = wordCount.count("bird");  
    cout<<"cnt"<<cnt<<endl;  
  
    //find方法:返回的是指向键的迭代器  
    int occurs = 0;  
    map<string,int>::iterator it = wordCount.find("bird");  
    if(it != wordCount.end())  
        occurs = it->second;  
    cout<<"occurs = "<<occurs<<endl;  
  
  
    //删除元素  
    int del;  
    string s1 = "hate";  
    //使用值删除  
    del = wordCount.erase(s1);  
    if(del)  
        cout<<s1<<" has been removed! "<<endl;  
    else  
        cout<<"can't find the word! "<<endl;  
  
    //使用迭代器删除  
    map<string,int>::iterator iter = wordCount.begin();  
    wordCount.erase(iter);  
  
  
    return 0;  
  
}  


二、Multimap

前面两种关联容器的特点是,键与值的对应关系是唯一的。而multimap或者multiset则支持一对多的关系。而且对于相同的键,总是连续的存储。由于这种一对多关系,所以multimap和multiset支持一些map和set没有的操作。比如lower_bound、upper_bound以及equal_range.它们分别返回的是指向某个键的第一个元素,最后一个元素的下一个元素以及这连个元素组成的范围。看一个综合例子:

#include <iostream>  
#include <map>  
#include <string>  
  
using namespace std;  
  
int main()  
{  
    multimap<string,string> authors;  
    string author,work,searchItem;  
  
    //建立作者及其作品的容器  
    do  
    {  
        cout<<"enter authors name"<<endl;  
        cin>>author;  
        if(!cin)  
            break;  
        cout<<"enter authors works"<<endl;  
        while(cin>>work)  
            authors.insert(make_pair(author,work));  
        cin.clear();  
    }while(cin);  
  
    cin.clear();  
    //删除元素  
  
    cout<<"who is the author that you want erase:"<<endl;  
    cin>>searchItem;  
    /* 
    //使用erase删除:输出对应键的所有值 
    multimap<string,string>::iterator iter = authors.find(searchItem); 
    if(iter != authors.end()) 
        authors.erase(searchItem); 
    else 
        cout<<"cannot find the author!"<<endl; 
    */  
  
    //使用equal_range或得迭代器删除  
    typedef multimap<string,string>::iterator itType;  
    pair<itType,itType> pos = authors.equal_range(searchItem);  
    if(pos.first != pos.second)  
        authors.erase(pos.first,pos.second);  
    else  
        cout<<"can not find this author!"<<endl;  
  
  
    //输出删除结果  
    cout<<"author\t\twork:"<<endl;  
    multimap<string,string>::iterator itbegin = authors.begin();  
    for(;itbegin != authors.end();++itbegin)  
        cout<<itbegin->first<<"\t\t"<<itbegin->second<<endl;  
  
    return 0;  
}  


三、Set

说完了map,我们在看看set。set只有键,没有值,所以他的vaule_type不是pair类型,而是key_type类型。同样的,它也支持insert、find、count操作。map比较适合于储存键值对应的情况,而set适合于储存键,判断键在不在这个集合中,比如黑名单之类的。

set容器是map的缩减版,只包含一个关键字 (关键字独一无二,只有一个,重复插入不做操作只是插入返回值会有显示)

map以键-值対的形式组织,键的作用在于索引,而值表示所存储和读取数据。

set仅包含一个键,并且有效的支持某个键是否存在的查询

//set使用练习:输出字符中不重复的字符

#include<set>
int main()
{
char c;
set<char> set_c;//创建set
while(cin.get(c))
set_c.insert(c);//插入,set不支持下标,insert返回pair,first指向元素,second是一个boll值,true表示插入成功,false表示已有元素
set<char>::iterator iterator=set_c.begin();//创建迭代器指向首
while(iterator!=set_c.end())
{
cout<<* iterator;//输出迭代器指向,只读,不可修改值
iterator++;
}
}


 参考博客:

http://blog.csdn.net/thefutureisour/article/details/7683656

猜你喜欢

转载自blog.csdn.net/alan_1550587588/article/details/77977741