关联容器:
关联容器与顺序容器的区别 在于 关联容器 是通过key 来存取 和读取 元素,顺序容器通过 容器中的位置 顺序存储和访问元素。 关联容器 是通过key -value方式工作的 。
关联容器类型:map 和set multimap 和 multiset map是 key-value set 是 只存放一个key。。 如字意表示:multimap 和 multiset 表示 可以存放 一个多次出现key
pair类型
pair是一个简单的标准库类型,和内置类型int 类似。这个类型中含有 2个数据类型,
int main()
{
pair< int, int > v;
pair< string, string > v1( "taotaosb", "taotaosb " );
pair< string, string > v2 = make_pair( "taotao sb", "haha" );
//这样使用是比较麻烦的,可以使用typedef 声明
typedef pair< string, string > Author;
Author s( "hehe", "haha" );
s.first = "sb"; //可以直接赋值
cout << s.first << s.second << endl;
cout << (v1 > v2) << endl;
cout << (v1 == v2) << endl;
cout << v1.first << " " << v2.second << endl;
}
pair 的 成员都是公有的,可以直接访问。
make_pair( , ) 可以生成一个pair对象。
关联容器:
map
关联容器 能使用 大部分 顺序容器操作。 不提供的 包括 front push_front back 等。 因为 关联容器要靠 key 来访问。不能以类似这种访问方式
构造函数:
不能通过容器大小来定义,否则无法知道key的类型。key必须 有一个能够实现比较的比较函数,键类型必须定义< 操作符 ,而且该操作符 必须能够“正确的工作",其他的关系或者相等运算,不做要求
map的类型:
map<k,v>::key_type 类型 是 const k类型
map<k,v>::mapped_type map容器中,键所关联的值的类型 这里是 V类型
map<k,v>::value_type pair类型,值成员可以修改,key成员不可以修改
map迭代器解引用就会产生一个 pair类型的对象。
给map添加 元素:
1) 使用 key下标 来 获取元素,然后给获取的元素赋值,
使用下标访问map对象的时候,如果不存在 这个元素将会在map容器中 添加一个新的元素,他的键就是该下标值。(如果存在就返回其值,如果不存在就插入一个新的元素),所关联的值 采用值初始化
// 3种构造方式
map< string, int > word_count ;
word_count["hehe"] = 1;
map< string, int >::iterator map_it = word_count.begin();
cout << (*map_it).first << " " << (*map_it).second << endl;
cout << word_count["haha"]; //打印为0
我们在最后一句访问的时候, 首先在map中搜索,如果没有,就插入 一个新的元素,关联值采用值初始话 ,也就是0 ++word_count["haha"]; //修改值 map下标返回的类型就是 值的类型, 而map的迭代器 返回的类型 是pair类型。
访问下标所表示的建在容器中不存在,则添加新元素,这个 特性 很好用
2)或者 采用insert成员
insert 中的参数 必须是 pair类型的 : 如果 参数的key不再 map中 则 插入,如果 存在,则 保持不变。该函数返回类型 是一个pair类型 ,包含一个map迭代器,和一个bool变量,表示是否插入了该元素。
map< string, int > word_count ;
pair< string, int > S( "hehe", 5 );
pair< map< string, int >::iterator, bool > ret;
ret = word_count.insert(S);
cout << (*(ret.first)).first << endl;
cout << ret.second << endl; //返回1,因为不存在,则插入成功
ret = word_count.insert(S);
cout << (*ret.first).first << endl;
cout << ret.second << endl; //返回0 因为 map中已经存在 ,不需要再次插入了
}
这中方式可以避免用下标那种方式中的 不必要的初始化。可以直接用make_pair节省 代码。
而用下标 和 insert 插入 有一个很重要的区别就是,用下标插入的时候,如果map中已经存在,则 更新与key对应的值,如果用insert ,如果已经存在的话,则不更新。看下面代码:
map< string, int > word_count ;
pair< map< string, int >::iterator, bool > ret;
ret = word_count.insert( make_pair( "hehe", 5 ) );
cout << (*ret.first).first << endl;
cout << (*ret.first).second << endl;
word_count.insert( make_pair( "hehe", 7 ) );
cout << (*ret.first).first << endl;
cout << (*ret.first).second << endl;
word_count["hehe"] = 7;
cout << word_count["hehe"] << endl;
打印结果:
可以看出来区别
insert(beg,end) 两个迭代器的 插入方式:
map< string, int > word_count ;
typedef pair< string, int > Author;
vector< Author > s;
s.push_back( make_pair( "chenhao", 1 ) );
s.push_back( make_pair( "taotao ", 2 ) );
s.push_back( make_pair( "chenhao1", 3 ) );
s.push_back( make_pair( "chenhao2", 4 ) );
vector< Author >::iterator itBegin = s.begin();
vector< Author >::iterator itEnd = s.end();
word_count.insert( itBegin, itEnd);
cout << word_count["chenhao"] << endl;
访问map中的元素
使用下标访问,这是比较危险的,因为 当你map中没有该元素的时候,会自动添加 该元素,并将 值 设置为默认初始值。有的时候我们不想插入元素,只向看看map中是不是存在该元素 。对于该类应用,不能采用下标来判断。则有两个函数可以选择 count(), 和find()
int main()
{
// 3种构造方式
map< string, int > word_count ;
typedef pair< string, int > Author;
vector< Author > s;
s.push_back( make_pair( "chenhao", 1 ) );
s.push_back( make_pair( "taotao ", 2 ) );
s.push_back( make_pair( "chenhao1", 3 ) );
s.push_back( make_pair( "chenhao2", 4 ) );
vector< Author >::iterator itBegin = s.begin();
vector< Author >::iterator itEnd = s.end();
word_count.insert( itBegin, itEnd);
//返回 存在的个数, map中肯定只能为 1 或者为0
cout << word_count.count( "chenhao" ) << endl;
map< string, int >::iterator iter;
//返回 一个指向该元素的 迭代器,如果不存在则返回超出末端迭代器,
iter = word_count.find( "taotao " );
cout << (*iter).first << endl;
iter = word_count.find( "taotaohah " );
cout << (*iter).first << endl;// 这里 是超出末端迭代器,这里解引用会出现错误,所以用的时候一定要小心
}
看下运行结果:从map中删除元素
// 3种构造方式
map< string, int > word_count ;
typedef pair< string, int > Author;
vector< Author > s;
s.push_back( make_pair( "chenhao", 1 ) );
s.push_back( make_pair( "taotao ", 2 ) );
s.push_back( make_pair( "chenhao1", 3 ) );
s.push_back( make_pair( "chenhao2", 4 ) );
vector< Author >::iterator itBegin = s.begin();
vector< Author >::iterator itEnd = s.end();
word_count.insert( itBegin, itEnd);
//删除map容器中的元素的3种方式
cout << word_count.count( "chenhao" ) << endl;
word_count.erase( "chenhao" );
cout << word_count.count( "chenhao" ) << endl;
map< string, int >::iterator iter = word_count.find("taotao ");
cout << ( *iter ).first << endl;
cout << word_count.count( "taotao " ) << endl;
word_count.erase( iter );
cout << word_count.count( "taotao " ) << endl;
打印输出:
1
0
taotao
1
0
3)erase(b,e) //b 和e都是指向 map中的两个迭代器
int main()
{
// 3种构造方式
map< string, int > word_count ;
typedef pair< string, int > Author;
vector< Author > s;
s.push_back( make_pair( "chenhao", 1 ) );
s.push_back( make_pair( "taotao ", 2 ) );
s.push_back( make_pair( "chenhao1", 3 ) );
s.push_back( make_pair( "chenhao2", 4 ) );
vector< Author >::iterator itBegin = s.begin();
vector< Author >::iterator itEnd = s.end();
word_count.insert( itBegin, itEnd);
map< string, int >::iterator iter1 = word_count.find( "chenhao" );
map< string, int >::iterator iter2 = word_count.find( "chenhao2" );
word_count.erase( iter1, iter2 );
cout << word_count.count( "chenhao") << endl;
cout << word_count.count( "taotao ") << endl;
cout << word_count.count( "chenhao1") << endl;
cout << word_count.count( "chenhao2") << endl;
}
看下打印的结果:
map对象的迭代遍历
int main()
{
// 3种构造方式
map< string, int > word_count ;
typedef pair< string, int > Author;
vector< Author > s;
s.push_back( make_pair( "chenhao", 1 ) );
s.push_back( make_pair( "taotao ", 2 ) );
s.push_back( make_pair( "chenhao1", 3 ) );
s.push_back( make_pair( "chenhao2", 4 ) );
vector< Author >::iterator itBegin = s.begin();
vector< Author >::iterator itEnd = s.end();
word_count.insert( itBegin, itEnd);
map< string, int >::iterator itsBegin = word_count.begin();
while( itsBegin != word_count.end() )
{
cout << itsBegin->first << " ";
cout << itsBegin->second << endl;
++itsBegin;
}
}
注意下打印结果:
注意下 我们可以看到map 容器 在插入的 时候 ,会自动排序 将 map中的元素 按照键的升序排列。。写个函数 验证下:
// 3种构造方式
map< string, int > word_count ;
typedef pair< string, int > Author;
vector< Author > s;
s.push_back( make_pair( "chenhao4", 1 ) );
s.push_back( make_pair( "chenhao3", 1 ) );
s.push_back( make_pair( "chenhao2", 1 ) );
s.push_back( make_pair( "chenhao1", 1 ) );
vector< Author >::iterator itBegin = s.begin();
vector< Author >::iterator itEnd = s.end();
word_count.insert( itBegin, itEnd);
map< string, int >::iterator itsBegin = word_count.begin();
while( itsBegin != word_count.end() )
{
cout << itsBegin->first << endl;
itsBegin ++;
}
打印结果:
chenhao1
chenhao2
chenhao3
chanhao4
OK,基本 满足要求。
使用 map 的 一个例子: C++primer 318 的题目
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <stack>
#include <map>
//默认的queue 和 queue 通过deque容器实现的 priority_queue 是在vector上实现的
using namespace std;
int main()
{
map< string, string > trans_map ;
trans_map.insert( make_pair( "'em", "them" ) );
trans_map.insert( make_pair( "cuz", "because" ) );
trans_map.insert( make_pair( "gratz", "grateful" ) );
trans_map.insert( make_pair( "i", "I" ) );
trans_map.insert( make_pair( "nah", "no" ) );
trans_map.insert( make_pair( "pos", "supposed" ) );
trans_map.insert( make_pair( "sez", "said" ) );
trans_map.insert( make_pair( "tanx", "thanks" ) );
trans_map.insert( make_pair( "wuz", "was" ) );
string input;
getline( cin, input );
string word;
string::size_type posBegin, posEnd = 0;
string separtor( " " );
map< string, string >::iterator itmap;
while( ( posBegin = input.find_first_not_of( separtor, posEnd ) ) != string::npos )
{
posEnd = input.find_first_of( separtor, posBegin );
if( posEnd == string::npos )
word.assign( input.begin() + posBegin, input.begin() + input.size() );
else
word.assign( input.begin() + posBegin, input.begin() + posEnd );
if( trans_map.count( word ) == 1)
{
itmap = trans_map.find( word );
cout << ( *itmap ).second << " ";
}
else
cout << word << " ";
}
cout << endl;
}
输入和输出:
OK,map先写 这么多。
set类型:
当只想知道 一个 值是否存在的时候, 使用set 容器是最合适的。 set 不支持 下标操作符。而且 没有 mapped_type 类型。 且 set容器中 存储的键 必须 唯一,且 不可以修改,而且值各不相同。
set 容器 满足 map 中的大部分操作
int main()
{
vector< int > ivec;
for( vector< int >::size_type i = 0; i != 10; i++ )
{
ivec.push_back( i );
ivec.push_back( i );
}
//第一种构造方式
set< int > iset( ivec.begin(), ivec.end() );
//插入方式
iset.insert( 10 );
cout << iset.size() << endl;
cout << ivec.size() << endl;
int data[] = { 11, 12, 13, 14};
//第二种插入方式
iset.insert( data, data + 4 );
cout << iset.size() << endl;
pair< set< int >::iterator, bool > pa;
pa = iset.insert( 17 );
cout << *( pa.first) << endl;
cout << ( pa.second) << endl;
//cout << iset.size() << endl;
}
insert 版本的 含有一个 键参数 仍然返回一个 pair 类型, 第一个成员是迭代器 ,第二个成员是 bool ,如果插入成功则返回真。
multimap 和 multiset
int main()
{
multimap< string, string > mmap;
mmap.insert( make_pair( "hehe","haha ") );
mmap.insert( make_pair( "hehe","heihei ") );
mmap.insert( make_pair( "hehe","sb ") );;
multimap< string, string>::iterator it = mmap.end();
mmap.erase( --it ); //返回为void类型
cout << mmap.erase( "hehe" ) << endl;
}
输出为: 2
在 multimap 和multiset 容器中,如果 某个键对应多个实例, 则这些 实例在容器中将相邻存放。
在 find 和 count 函数中,count 返回 个数, find 返回一个迭代器,指向 第一个实例。
那么如何 打印出来 一个键对应的所有元素呢,有3种方法,我们依次来看一下。
1)
int main()
{
multimap< string, string > mmap;
mmap.insert( make_pair( "hehe","haha ") );
mmap.insert( make_pair( "hehe","heihei ") );
mmap.insert( make_pair( "hehe","sb ") );;
multimap< string, string >::iterator it;
it = mmap.find( "hehe" );
int n = mmap.count( "hehe" );
for( int i = 0; i < n ; i++ ,it++)
{
cout << ( *it ).second << " ";
}
return 0;
}
利用 count返回的个数,一个一个的打印。
2) 特殊 的解决方案
lower_bound(k) 返回一个迭代器,指向键不小与k的第一个元素
upper_bound(k) 返回一个迭代器,指向键大于k的第一个元素
equal_range(k)返回一个迭代器的pair对象,第一个成员就是 lower_bound(k) 返回的迭代器,第二个成员就是 upper_bound(k) 返回的迭代器。
int main()
{
multimap< string, string > mmap;
mmap.insert( make_pair( "aaaa","haaa ") );
mmap.insert( make_pair( "bbbb","bfsg ") );
mmap.insert( make_pair( "hehe","haha ") );
mmap.insert( make_pair( "hehe","heihei ") );
mmap.insert( make_pair( "hehe","sb ") );
mmap.insert( make_pair( "zzze","hsgsa ") );
multimap< string, string >::iterator itLower;
multimap< string, string >::iterator itUpper;
typedef multimap< string, string >::iterator S;
pair< S,S > itPair;
itLower = mmap.lower_bound( "hehe" );
itUpper = mmap.upper_bound( "hehe" );
cout << itLower -> second << endl;
cout << itUpper -> second << endl;
return 0;
}
结果:
haha
hsgsa