zoukankan      html  css  js  c++  java
  • 关联容器操作

    • 对于 set 类型,key_typevalue_type 是一样的,set 中保存的值就是关键字。
    • 在一个 map 中,元素时关键字-值对,即,每个元素都是一个 pair 对象,包含一个关键字和一个关联的值,由于我们不能改变一个元素的关键字,因此这些 pair 的关键字部分是 const 的。
    set<string>::value_type v1;			//v1是string
    set<string>::key_type v2;			//v2是string
    map<string, int>::value_type v3;	//v3是pair<const string,int>
    map<string, int>::key_type v4;		//v4是string
    map<string, int>::mapped_type v5;	//v5是int
    

    注意:

    只有 map 类型(unordered_map、unordered_multimap、multimap、map)才定义了 mapped_type 类型。

    关联容器迭代器

    解引用一个关联容器将得到一个类型为容器的 value_type 的值得引用。

    map<string, size_t>  word_count;
    auto map_it = word_count.begin();
    cout << map_it->first;
    cout << map_it->second;
    map_it->first = "new key";	//错误,关键字是const类型
    ++map_it->second;	//正确,可以通过迭代器改变元素的值
    

    注意:

    一个 mapvalue_type 是一个 pair 类型,可以改变 pair 的值,但是不能改变关键字成员的值。

    set 的迭代器是 const 的

    虽然 set 同时定义了关键字 iteratorconst_iterator 类型,但两种类型都只允许访问 set 的元素,不允许改变,即,set 的关键字是 const 类型的。

    set<int> iset = { 0,1,2,3,4,5,6 };
    set<int>::iterator set_it = iset.begin();
    if (set_it != iset.end())
    {
    	*set_it = 42;		//错误,set中的值是只读的
    }
    

    历关联容器

    mapset 都支持 beginend 操作,可以使用这些函数获取迭代器,然后使用迭代器来遍历容器。

    map<string, size_t>  word_count;
    auto map_it = word_count.cbegin();
    while (map_it != word_count.cend())
    {
        cout << map_it->first << " occurs " << map_it->second << " times" << endl;
        ++map_it;
    }
    

    注意:

    当使用一个迭代器遍历一个 mapmultimapsetmultiset 时,迭代器按关键字升序遍历元素。

    关联容器和算法

    通常不会对关联容器使用泛型算法。

    关键字 const 的特性意味着不能讲关联容器传递给修改元素或者重排元素的算法,而 set 的关键字是 const的,map 的键是 const 的。

    关联容器可以用于只读算法,但是这类算法通常都要搜索序列,由于关联容器中的元素不能通过它们的关键字进行快速查找,因此对其使用泛型算法几乎总是个坏主意。

    在实际编程时,要对关联容器使用算法的情况:

    • 把关联容器当作一个源序列。可以使用泛型算法 copy 将元素从一个关联容器拷贝到另一个序列。
    • 把关联容器当作一个目的位置。可以调用 insert 将一个插入器绑定到一个关联容器,通过使用 insert,可以将关联容器当作一个目的位置来调用另一个算法。

    添加元素

    insert 向容器中添加一个元素或一个元素范围。

    mapset (以及对应的无序类型)包含不重复的关键字,因此插入一个已存在的元素对容器没有任何影响。

    vector<int> ivec = { 2,4,6,8,2,4,6,8 };
    set<int>	iset;
    iset.insert(ivec.cbegin(), ivec.cend());	//iset包含4个元素
    iset.insert({ 1,3,5,7,1,3,5,7 });	//iset包含8个元素
    

    向 map 添加元素

    对一个map insert时候,需要记住元素类型是 pair,通常需要在insert的参数类别中创建一个pair:

    map<string, size_t> word_count;
    word_count.insert({ "word",1 });
    word_count.insert(make_pair("word", 1));
    word_count.insert(pair<string,size_t>("word",1));
    word_count.insert(map<string, size_t>::value_type("word", 1));
    

    检测 insert 的返回值

    insertemplace 的返回值依赖于容器类型和参数。对于不包含重复关键字的容器,添加单一元素的额insertemplace 版本返回一个 pair

    • pairfirst 成员是一个迭代器,只向具有给定关键字的元素。
    • pairsecond 成员是一个 bool 值,指出元素是插入成功还是已经存在于容器中,如果关键字已经在容器中,则 insert 什么也不做,且返回值中的 bool 部分为 false 。如果关键字不存在,元素被插入,且 bool 返回 true
    map<string, size_t> word_count;
    string word;
    while (cin >> word)
    {
        auto ret = word_count.insert({ word, 1 });
        if (!ret.second)
       		++ret.first->second; //递增计数值
    }
    
    • ret 保存了 insert 的返回值,是一个 pair 类型。
    • ret.firstpair 的第一个成员,是一个 map 迭代器,指向具有给定关键字的元素。
    • ret.first-> 解引用此迭代器,提取 map 中的元素,元素也是一个 pair
    • ret.first->second map中元素的值部分。
    • 实际上 ret 声明和初始化方式为:
    pair<map<string, size_t>::iterator, bool> ret = word_count.insert(make_pair<word,1>);
    

    向 multiset 或 multimap 中添加元素

    multi 容器中的关键字不必唯一,因此在这些类型上的调用 insert 总会插入一个元素。

    multimap<string, string> authors;
    //插入一个元素,关键字是:Barth,Join
    authors.insert({ "Barth,Join","Sot-Weed Factor" });
    //插入一个元素,关键字还是:Barth,Join
    authors.insert({ "Barth,Join","Lost in the Funhouse" });
    

    对于允许重复关键字的容器,接受单个元素的 insert 操作返回一个指向新元素的迭代器,这里不需要返回bool 值,因为总是可以插入元素。

    删除元素

    关联容器提供了三个版本的 erase:

    • 传递给 erase 一个迭代器来删除一个元素,返回 void
    • 传递给 erase 一个迭代器对来删除一个元素范围,返回 void
    • 传递给 erase 一个 key_type 参数,删除所有匹配关键字的元素(如果存在的话),它返回实际删除的元素的数量。
      • 对于保存不重复关键字的容器,erase 总是返回0或者1。
      • 对于可重复关键字的容器,erase 可能返回大于1。

    map 的下标操作

    • mapunordered_map 容器提供了下标运算符和一个对应的 at 函数。
    • set 不支持下标,因为set中没有与关键字关联的值。
    • 不能对一个 multimap 或一个 unordered_multimap 进行下标操作,因为这些容器中可能有多个值与关键字关联。

    map 下标运算符接受一个索引,即一个关键字,获取与此关键字相关联的值。如果关键字不在 map 中,会为它创建一个元素病插入到 map 中,关联值则进行值初始化。

    map<string, size_t> word_count;	//空的map
    word_count["Anna"] = 1;
    

    执行的操作为:

    • word_count 搜索关键字为 Anna 的元素,没有找到。
    • 将一个新的关键字-值对插入到 word_count 中,关键字是一个 const string,保存 Anna,值进行值初始化,在此意味着0。
    • 提取出新插入的元素,将值1赋予它。

    访问元素

    关联容器提供了多种查找一个指定元素的方法:

    如果只关心一个特定元素是否已在容器中,使用 find 是最佳的选择,对于关键字不允许重复的容器,使用 find 和使用 count 没什么区别,但是对于允许关键字重复的容器,count 可以统计多少个元素有相同的关键字,当然如果不需要计数,则可以直接用 find

    在 multimap 或 multiset 中查找元素

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

    查找给定作者的著作:

    string search_item("Alain de Botton");	//指定作者
    auto entries = authors.count(search_item);	//元素的数量
    auto iter = authors.find(search_item);	//此作者的第一本书
    while(entries){
    	cout<<iter->second<<endl;
    	++iter;
    	--entries;
    }
    

    一种不同的,面向迭代器的解决办法

    lower_boundupper_bound 可以获取具有相同关键字的一个迭代器范围。这两个操作有可能返回的迭代器是尾后迭代器:

    • 如果查找的元素具有容器中最大的关键字,则此关键字的 upper_bound 返回尾后迭代器。
    • 如果关键字不存在,且大于容器中任何关键字,则 lower_bound 返回的也是尾后迭代器。

    注意:

    lower_bound 返回的迭代器可能指向一个具有给定关键字的元素,但也可能不指向。如果关键字不在容器中,则lower_bound 会返回关键字的第一个安全插入点---- 不影响容器中元素顺序的插入位置。

    重写上面的操作:

    for (auto beg = authors.lower_bound(search_item), beg = authors.upper_bound(search_item);
    	beg != end; ++beg)
    cout << beg->second << endl;
    

    注意:

    如果 lower_boundupper_bound 返回相同的迭代器,则给定关键字不在容器中。

    equal_range 函数

    equal_range 函数接受一个关键字,返回一个迭代器 pair,若关键字存在,则第一个迭代器指向第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配关键字之后的位置。如果没有找到匹配的元素,则两个迭代器都指向关键字可以插入的位置。

    再次修改上面的程序:

    for(auto pos = authors.equal_range(search_item);
    	pos.first != pos.second;++pos.first_
    cout<< pos.first->second<<endl;
    
  • 相关阅读:
    BZOJ 3053 The Closest M Points
    Python 语言介绍
    计算机组成与操作系统基础
    Gym 100818I Olympic Parade(位运算)
    Codeforces 602B Approximating a Constant Range(想法题)
    Codeforces 599D Spongebob and Squares(数学)
    Codeforces 599C Day at the Beach(想法题,排序)
    ZOJ 3903 Ant(数学,推公示+乘法逆元)
    ZOJ 3911 Prime Query(线段树)
    UVALive 6910 Cutting Tree(离线逆序并查集)
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/12496884.html
Copyright © 2011-2022 走看看