C++学习笔记(十)

第十一章 关联容器

1.关联容器与顺序容器有着根本的不同:关联容器中的元素是按照关键字来访问和保存的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。不同之处反映了关键字的作用。

2.关联容器支持高效的关键字查找和访问。两个最主要的关联容器是map和set。

3.map中的元素是一些关键字-值对:关键字起到索引的作用,值代表与索引相关联的数据。例如字典:单词为关键字,意思为值。

    map<string,size_t> count;

    map类型通常被称为关联数组,与普通数组的不同在于,map的下标不必是整数,可以通过一个关键字而不是位置来查找值。

    set中的元素只包含一个关键字,set支持高效的关键字查询操作。例如:在文本处理中用set来保存想要忽略的单词。

    set<int> num;

    当想要知道一个值是否存在时,使用set是最有用的。

4. 

map / set      不允许重复关键字

multimap / multiset 是允许重复关键字的容器(允许多个元素具有相同的关键字),元素是有序的

unordered_map / unorder_set 是元素无序保存的容器,不允许重复关键字

unordered_multimap / unordered_nultiset 是允许关键字重复,且无序的容器

5. 标准库类型pair,定义在头文件utility中,一个pair保存两个数据成员,pair<string,int> a;他们是public的,两个成员分别为first和second,用成员访问符号“.”来访问。即a.first 和a.second。

    map的每个元素都是一个pair对象!

6. 关联容器关键字和值的类型:

    key_value 此容器类型关键字类型

    mapped_type 每个关键字所关联的值的类型,只适用于Map

    value_type   对于set,与key_value相同;对于map,为pair<const key_type, mapped_type> 可以改变一个pair的值,但不能改变一个元素的关键字,是const的。

7. 当解引用一个关联容器迭代器时,会得到一个类型为容器的value_type的值的引用。

     对于map来说是一个pair类型,对于set;来说是一个key_value类型。一个set关键字也是const的,只能读取不能修改。

    例:

        map<string, size_t> word_count;
	auto map_it = word_count.begin();
	//*map_it 指向一个pair<const string,size_t>对象的引用;
	cout << map_it->first;       //打印此元素的关键字
	cout << map_it->second;      //打印此元素的值
	++map_it->second;            // 即 (++(*map_it).second;)
        set<int> set = { 1, 2, 3, 4, 5 };
	auto set_it = set.begin();
	cout << *set_it << endl;     //读取关键字
set类型中的元素是const的,map中元素是pair,其第一个成员是const。所以通常不对关联容器使用泛型算法。而实现其它功能可以使用关联容器专门定义的函数成员。

8.添加元素

关联容器的insert成员向容器中添加一个元素或元素范围,由于map和set不包含重复的关键字,所以插入一个已存在的元素对容器没有影响。

insert有两个版本:接受一对迭代器和一个初始化列表

(1)set的添加:

        vector<int> ivec = { 1, 2, 3, 4, 5, 6 };
	set<int> sett;
	sett.insert(ivec.cbegin(), ivec.cend());
	sett.insert({ 7, 8, 9, 0 });
对于一个给定的关键字,只有第一个带此关键字的元素才被插入到容器中。
(2)map的添加:

对一个map进行insert操作时必须记得元素类型是pair。

	map<string, size_t> word_count;
	string word;
	while (cin >> word){
		auto ret = word_count.insert({ word, 1 });                               方法1  
		auto ret = word_count.insert(make_pair(word,1));                         方法2
		auto ret = word_count.insert(pair<string,size_t>(word,1));               方法3
		auto ret = word_count.insert(map<string,size_t>::value_type(word,1));    方法4

(3)insert返回值:

insert返回的值依赖于容器类型和参数,对于不包含重复关键字的容器,添加单一元素的insert版本返回一个pair,来说明是否插入成功。
pair的first成员是一个迭代器,指向具有给定关键字的元素;second成员是一个bool值,说明插入成功或者已存在于容器中。如果关键字已存在,返回false,如果不存在,但会true。

例:统计每个单词出现次数

	map<string, size_t> word_count;
	string word;
	while (cin >> word){
		auto ret = word_count.insert({ word, 1 });                               //方法1  
		//auto ret = word_count.insert(make_pair(word,1));                         方法2
		//auto ret = word_count.insert(pair<string,size_t>(word,1));               方法3
		//auto ret = word_count.insert(map<string,size_t>::value_type(word,1));    方法4
		if (!ret.second)
			++ret.first->second;
	}
输入第一个word,将word和其值1存入到map中,此时返回的pair的第二个成员bool返回ture,所以不进行之后的累加;如果之后再次输入同样的word,会将word和其计数值1再次存入map中,但此时Bool返回一个false.if的条件变为真,所以进行累加,讲1累加为2,说明这个word出现了2次。

++ret.first->second  即++((ret.first)->second);

ret是添加word之后返回的pair类型。

ret.first是一个迭代器,只想该pair中具有给定关键字的元素。(指向的是元素)
ret.first->second 解引用该元素(  (*ret.first).second  ),提取该关键字所关联的值(之前为1的那个值)。     之后进行累加1+1=2 

9.删除元素

通过传递给erase一个迭代器或者一个迭代器范围来删除一个或一个元素范围。指定的元素被删除,返回void。

或者接受一个key_value参数,来删除给定关键字的元素,返回实际删除元素的数量。对于不重复的容器,返回值为0或者1。为0时表示该元素不在容器中。

word_count.erase(removal_word);   返回一个size_type的值,指出删除的元素的数量;

word_count.erase(p);        p是一个迭代器,返回指向P之后元素的位置,若P指向尾元素,则返回尾后迭代器。

举例:删除multimap的同一作者的所有元素

#include<map>
#include<iostream>
#include<string>
#include<algorithm>
using namespace::std;
int main(){
	multimap<string, string> test={{ "li", "a" }, { "gong", "b" }, { "he", "c" }, { "li", "d" }, {"gong","e"}};
	string a1 = ("gong");
	for (auto beg = test.equal_range(a1); beg.first!=beg.second;){
			auto r=test.erase(beg.first);
			beg.first=r;
	}//方法一 用equal_range

	for (auto beg = test.lower_bound(a1), end = test.upper_bound(a1); beg != end;){
		auto r = test.erase(beg);
		beg= r;
	}//方法二 用lower 或者 upper


	for (const auto& t : test)
		std::cout << t.first << " " << t.second << std::endl;
	return 0;
}
因为erase返回的迭代器的下一个位置,所以将其赋值给beg,而不用beg自己累加。

10. map的下标操作

map下标操作接受一个关键字,或许与此关键字关联的值。但是,与其他下标操作不同的是,如果关键字并不再map中,会为其创建一个元素并将其插入到map中,所关联的值将进行值初始化。所以,map下标操作有可能会插入一个新元素,只可以对非const的map使用下标操作。

除此之外,对map进行下标操作时,会获得一个mapped_type对象,也就是其关联的值。

                    当解引用一个map迭代器时,会得到一个value_type对象。如上7所述。

map的下标操作返回一个左值(一个对象或函数)

11. 访问元素

(1)word_count.find(k)       查找:返回一个迭代器,指向第一个关键字为K的元素,若K不在容器中,则返回word_count.end( )

(2)word_count.count(k)    计数:返回关键字等于K的元素的数量。对于不允许重复的迭代器,返回永远是0或1

(3)如果一个multimap或multiset中有多个元素具有给定的关键字,则这些元素会在容器中相邻存储。

          word_count.lower_bound(k)  返回一个迭代器,指向第一个具有给定关键字的元素

          word_count.upper_bound(k)  返回一个迭代器,指向最后一个具有给定关键字的元素之后的位置

lower_bound和upper_bound其不适用于无序容器;

如果元素不再multimap中,则他俩会返回相等的迭代器——指向不影响排序的关键字插入位置。一个安全位置。

(4)word_count.equal_range(k)   返回一个迭代器pair,表示关键字等于k的元素的范围,若k不存在,则pair的两个成员都是尾后迭代器

若关键字存在,则第一个迭代器指向第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配元素之后的位置。

12. 无序容器

无序容器在存储上组织为一组桶,每个桶保存0个或者多个元素,无序容器使用一个哈希函数将元素映射到桶。容器将具有一个特定哈希值的所有元素都保存在相同的桶中。所以无序容器的性能依赖于哈希函数的质量和桶的数量和大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值