C++学习笔记(五):关联容器--map与set

来源:互联网 发布:windows 网页白名单 编辑:程序博客网 时间:2024/05/31 18:47
关联容器支持通过键来高效地查找和读取元素。  两个基本的关联容器是map和set。

map的元素以键-值对的形式组织: 键用作元素在map中的索引, 而值表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。


关联容器类型

map  关联数组,元素通过键来存储和读取
set    大小可变的集合,支持通过键实现的快速读取

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

set和map的区别
如果希望有效存储不同的值,则需要用set, 而map则是 适合存储每个键所关联的值的情况。

关联容器支持很多顺序容器也提供的操作, 此外,还提供管理或使用键的特殊操作。  

关联容器 相关的简单的标准库类型:  pair类型, 该类型在utility头文件中定义

默认格式:
pair< T1, T2 > p1; T1和T2为两种类型

初始化格式:
pair<T1, T2> p1(v1, v2), 第一元素初始化v1, 第二元素初始化为v2。

make_pair(v1, v2) 创建一个新的pair对象

p1 < p2 , p1 == p2 表示对象之间的小于等于运算, 其定义遵循字典次序

p.first  和 p.second 返回first和 second两个共有成员

pari对象的操作
与其他标准库类型不同,对于pair类, 可以直接访问其数据的成员: 其成员都是公有的, 分别命名为first, second。 

生成新的pair对象
 除了构造函数,标准库还定义了一个make_pair函数, 由传递给它的两个实参生成一个新的pair对象。  可如下使用该函数来创建新的pair对象,并赋给已存在的pair对象:

pair<string, string > next_auth;
while(cin>>first>>last){
     next_auth=make_pair(first, last);
}


关联容器

关联容器共享大部分的顺序容器操作:

关系运算;
begin, end, rbegin, rend这些操作的迭代器

类型别名: 对于map容器,value_type并非元素的类型

赋值操作和swap交换操作。  但关联容器不提供assign函数

列出的clear和erase操作,erase操作返回void类型

关于容器大小的操作size(), 但是不能用resize函数


但它不提供 front、 push_front、pop_front、back、 push_back以及pop_back操作

关联容器不能通过大小来定义,, 因为这样的话就无法知道键所对应的值是什么, 也就是必须一个一个去构建关联。



结合一些应用, 下面主要介绍下关联容器:
map类型

map是键-值对的集合,  map类型通常可理解为关联数组: 可使用键作为下标来获取一个值, 正如内置数组类型一样。 而关联的本质在于元素的值与某个特定的键相关联, 而并非通过元素在数组中的位置来获取。

map对象的定义

要使用map对象, 则必须包含map头文件。  在定义map对象时,必须分别指明键和值得类型:

map<string, int> word_count;  这个语句表示定义了一个名为 word_count的map对象, 由string类型的键索引, 关联的值则为 int 型。


map的构造函数
map<k, v>m;               创建一个空对象

map<k, v> m(m2);       m与m2必须有相同的键类型和值类型
map<k, v> m(b, e);       存储迭代器b和e 标记的范围内多有元素的副本。  元素的类型必须能转换为pair<const k, v>

键类型的约束,  它提供了一个比较函数,  比较函数必须在键类型上定义 严格弱排序。  所谓严格弱排序可理解为键类型数据上的“小于”关系。 这种小于关系,在元素之间具有传递关系。     当两个元素无法比较谁小时, 可以将它们视为相同的元素。


Map定义的类型

map对象的元素时键-值对, 也即每个元素包含两个部分: 键以及由键关联的值。   map的value_type反映了这个事实。 该类型是存储元素的键以及值得pair类型, 而且键位const。

map迭代器进行解引用将产生pair类型的对象:

对迭代器进行解引用时,将获得一个引用, 指向容器中一个value_type类型的值。 对于map容器,其value_type是pair类型:


map<string, int>:: iterator map_it = word_count.begin();
map_it->first 为键  map_it->second 为值

map容器额外定义的类型别名
map类额外定义的两种类型: key_type和mapped_type, 以获得键或值得类型。 如同顺序容器一样,可使用作用域操作符来获取类型成员, 如map<string, int>:: key_type

给map添加元素

定义了map容器后, 
在容器中添加键-值元素对。 该项工作可使用insert成员实现;  或者,先用下标操作符获取元素,然后给获取的元素赋值。 

使用下标访问map与使用下标访问数组或vector的行为截然不同:用下标访问不存在的元素将导致在map容器中添加一个新的元素, 它的键即为该下标值。



下标操作符返回值的使用
下标操作符返回左值。 它返回的左值是特定键所关联的值。

map迭代器返回value_type类型的值,  包含 const key_type 和 mapped_type 类型成员的pair对象;  下标操作符则返回一个mapped_type类型的值

下标行为的编程意义:
对于map容器, 如果下标所表示的键在容器中不存在, 则添加元素, 这一特性可使程序惊人地简练:

map<string, int> word_count;

string word;
while(cin>>word)
    ++word_count[word];

//这段代码  是告诉我们,如果 map中没有pair元素,则添加一个键值为 word的元素, 默认构造函数将其初始化为0,然后加1

map:: insert的使用

map容器的insert成员与顺序容器的类似,但有一点要注意:  必须考虑键的作用。 

m.insert(e)  e       是一个用在m上的value_type类型的值。如果键(e.first)不再m中,则插入一个值为e.second的新元素; 如果该键在m中已存在,则保持m不变。 并且,该函数返回一个pair类型对象, 包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素

m.insert(beg, end)       beg和end标记的元素范围返回的类型value_type类型为键-值对。 返回void类型

m.insert(iter, e);      在iter位置,插入类型为value_type的e,  e.first如果不在键值中,则创建;如果在 ,则不插入, 返回一个迭代器,指向m中具有给定键的元素


以insert代替下标运算
word_count.insert(map<string, int>::value_type("Anna", 1);
使用insert成员可避免使用下标操作所带来的副作用:不必要的初始化。

检测 insert 的返回值

对于插入带有一个键-值 pair形参的insert版本将返回一个值: 包含一个迭代器和一个bool值得pair对象, 其中迭代器不管bool值是false还是true,都将指向该键所对应的的元素。

查找并读取map中的元素:
 查找:
map容器提供了两个操作:count和find, 用于检查某个键是否存在而不会插入该键

不修改map对象的查询操作
m.count(k)  返回m中k的出现次数
m.find(k) 如果m容器存在按k索引的元素,则返回指向钙元素的迭代器,如果不存在,则返回值超出末端迭代器。

count一般用于检查,一个索引键是否存在,而find一般可以 读取元素,而不插入
具体看如下代码:

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





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


erase操作
从map对象中删除元素, 位移与顺序容器不一样的地方就在于,其返回的值为一个空类型

map对象的迭代遍历:
一般,我们在进行遍历操作时, 是不希望进行修改元素值得。
map<string, int>::const_iterator map_it= world_count.begin();

while(map_it != word_count.end()){
     cout<<map_it->first<<" occurs"
          <<map_it->second<<" times"<<end;
     ++map_it;
}

在使用迭代器遍历map容器时,迭代器指向的元素按键的升序排列。


关于主函数的两个实参: int argc, char *argv.  程序执行时,首先检查实参的个数,即argc。 第一个实参 argv[0]是命令名, 而执行该程序所需要的两个文件名参数则分别存储在argv[1]及argv[2]中。 可以将argv[1]和argv[2]当做一个变量来操作,一般是路径名

set类型
set容器只是单纯键的集合。当只想知道一个值是否存在时,使用set容器是最适合的。 相比map容器,set只有两种操作不支持:

1 set不支持下标操作符, 而且没有定义mapped_type类型
2 在set容器中,value_type不是pair类型,而是与key_type相同的类型。

与set一样,set容器存储的键也必须唯一,而且不能修改。

set容器的定义和使用
为了使用set容器,必须包含set头文件,set支持的操作基本上与map提供的相同

如果将一个顺序容器的所有元素存入set容器中,则set容器就变成了元素值没有重复出现的顺序容器。

在set中添加元素
使用insert操作:
set<string> set1;
set1.insert("the");
set1.insert("and");

如果不想一个个的输入,可以使用一对迭代器来初始化:
set<string> set1;
set1.insert(ivec.begin(), ivec.end());


从set中获取元素
set容器不提供下标操作符.  为了通过键从set中获取元素, 可使用find运算。 如果只需简单地判断某个元素是否存在,同样可以使用count运算,返回set中该键对应的元素个数。 










0 0
原创粉丝点击