学习C++ primer的关键点记录二

关联容器(map、set、multimap、multiset)的元素按键排序和访问。关联容器支持通过键高效地查找和读取元素。键的使用,使关联容器区别于顺序容器(vector、list、deque)和顺序适配器容器(stack、queue、priority_queue),顺序容器的元素是根据位置访问的。

map 和 multimap 类型存储的元素是键-值对。它们使用在 utility 头文件中定义的标准库 pair 类,来表示这些键-值对元素。对 map 或 multimap 迭代器进行解引用将获得 pair 类型的值。pair 对象的 first 成员是一个 const键,而 second 成员则是该键所关联的值。set 和 multiset 类型则专门用于存储键。在 map 和 set 类型中,一个键只能关联一个元素。而 multimap 和multiset 类型则允许多个元素拥有相同的键。

1:map 容器是键-值对的集合,map的键必须唯一,而且不能修改。


value_type 是 pair <const K,V>类型,它的值成员可以修改,但键成员不能修改。map 迭代器返回 value_type 类型的值——包含 const key_type 和mapped_type 类型成员的 pair 对象,它的 first 成员存放键,为const,而 second 成员则存放值。下标操作符则返回一个 mapped_type 类型的值。

map的插入操作:

map<string, int> word_count;

word_count.insert(map<string, int>::value_type("Anna", 1));

使用 make_pair:

word_count.insert(make_pair("Anna", 1));

使用 typedef:

typedef map<string,int>::value_type valType;
word_count.insert(valType("Anna", 1));

查找并读取 map 中的元素:

下标操作符给出了读取一个值的最简单方法:
map<string,int> word_count;
int occurs = word_count["foobar"];

使用下标存在一个很危险的副作用:如果该键不在 map 容器中,那么下标操作会插入一个具有该键的新元素。

这样的行为是否正确取决于程序员的意愿。在这个例子中,如果“foobar”不存在,则在 map 中插入具有该键的新元素,其关联的值为 0。在这种情况下,occurs 获得 0 值。

map 容器提供了两个操作:count 和 find,用于检查某个键是否存在而不会插入该键。

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

从 map 对象中删除元素:

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

map 对象的迭代遍历:

// get iterator positioned on the first element
map<string, int>::const_iterator map_it = word_count.begin();
// for each element in the map
while (map_it != word_count.end()) {
    // print the element key, value pairs
    cout << map_it->first << " occurs "<< map_it->second << " times" << endl;
    ++map_it; // increment iterator to denote the next element
}

2: set 容器只是单纯的键的集合

set 容器支持大部分的 map 操作,两种例外包括:set 不支持下标操作符,而且没有定义 mapped_type 类型。在 set 容器中value_type 不是 pair 类型,而是与 key_type 相同的类型。与 map 一样,set 容器存储的键也必须唯一,而且不能修改。

3:multimap 和 multiset 类型:map 和 set 容器中,一个键只能对应一个实例。而 multiset 和 multimap类型则允许一个键对应多个实例,multimap 和 multiset 所支持的操作分别与 map 和 set 的操作相同,只有一个例外:multimap 不支持下标运算。

4:泛型算法

标准库容器定义的操作非常少。标准库没有给容器添加大量的功能函数,而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是“泛型”的,可作用在不同类型的容器和不同类型的元素上,标准容器(the standard container)定义了很少的操作。大部分容器都支持添加和删除元素;访问第一个和最后一个元素;获取容器的大小,并在某些情况下重设容器的大小;以及获取指向第一个元素和最后一个元素的下一位位置的迭代器。用户可能还希望对容器元素进行更多其他有用的操作:也许需要给顺序容器排序,或者查找某个特定的元素,或者查找最大或最小的元素,等等。标准库并没有为每种容器类型都定义实现这些操作的成员函数,而是定义了一组泛型算法。自定义的容器类型只要与标准库兼容,同样可以使用这些泛型算。大多数算法是通过遍历由两个迭代器标记的一段元素来实现其功能法。每个泛型算法的实现都独立于单独的容器。这些算法还是大而不全的,并且不依赖于容器存储的元素类型。只在一点上隐式地依赖元素类型:必须能够对元素做比较运算。泛型算法本身从不执行容器操作,只是单独依赖迭代器和迭代器操作实现。算法基于迭代器及其操作实现,而并非基于容器操作。这个事实也许比较意外,但本质上暗示了:使用“普通”的迭代器时,算法从不修改基础容器的大小。正如我们所看到的,算法也许会改变存储在容器中的元素的值,也许会在容器内移动元素,但是,算法从不直接添加或删除元素。

泛型算法必须包含 algorithm 头文件:#include <algorithm>

标准库还定义了一组泛化的算术算法,必须包含 numeric 头文件:#include <numeric>

所有算法都在一段范围内的元素上操作,带有输入范围参数的算法总是使用头两个形参标记该范围。这两个形参是分别指向要处理的第一个元素和最后一个元素的下一位置的迭代器。理解算法的最基本方法是了解该算法是否读元素、写元素或者对元素进行重新排序。

5:迭代器

标准库所定义的迭代器(iterator、const_iterator)不依赖于特定的容器。事实上,C++ 语言还提供了另外三种迭代器:
• 插入迭代器:这类迭代器与容器绑定在一起,实现在容器中插入元素的功能。
• iostream 迭代器:这类迭代器可与输入或输出流绑定在一起,用于迭代遍历所关联的 IO 流。
• 反向迭代器:这类迭代器实现向后遍历,而不是向前遍历。所有容器类型都定义了自己的 reverse_iterator 类型,由 rbegin 和 rend 成员函数返回。
上述迭代器类型都在 iterator 头文件中定义。

插入迭代器,C++ 语言提供了三种插入迭代器(插入迭代器是一种迭代器适配器带有一个容器参数,并生成一个迭代器,用于在指定容器中插入元素),其差别在于插入元素的位置不同

back_inserter,创建使用 push_back 实现插入的迭代器。
front_inserter,使用 push_front 实现插入。
inserter,使用 insert 实现插入操作。除了所关联的容器外,inserter还带有第二实参:指向插入起始位置的迭代器。

 iostream 迭代器,虽然 iostream 类型不是容器,但标准库同样提供了在 iostream 对象上使用的迭代器:istream_iterator 用于读取输入流,而 ostream_iterator 则用于写输出流。这些迭代器将它们所对应的流视为特定类型的元素序列。使用流迭代器时,可以用泛型算法从流对象中读数据(或将数据写到流对象中)。

反向迭代器是一种反向遍历容器的迭代器。也就是,从最后一个元素到第一个元素遍历容器。反向迭代器将自增(和自减)的含义反过来了:对于反向迭代器,++ 运算将访问前一个元素,而 -- 运算则访问下一个元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值