关联容器概述

Posted xiaojianliu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关联容器概述相关的知识,希望对你有一定的参考价值。

关联容器支持高效的关键字查找和访问。两个主要的关联容器:map、set。

map 中的元素是一些键-值对,关键字起到索引的作用,值表示与索引相关联的数据。

set 中每个元素都只包含一个关键字,set支持高效的关键字查询操作-----检查一个关键字是否在set中。

标准库提供了8个关联容器,8个容器间的不同体现在三个维度:

  • 或者是 set 或者是 map。
  • 或者要求不重复的关键字,或者允许重复的关键字。
  • 按顺序保存元素或者无序保存元素。

头文件 :

  • mapmultimap 定义在头文件 map 中。
  • setmultiset 定义在头文件 set 中。
  • 无序容器则定义在 unordered_mapunordered_set 中。
    技术图片

关联容器不支持顺序容器的位置相关的操作,例如 push_frontpush_back 操作。原因是关联容器中的元素是根据关键字来存储的,这些操作对于关联容器没有意义。

关联容器也不支持构造函数或插入操作这些接收一个元素值和一个数量值的操作。

关联容器是双向的。

定义关联容器

定义关联容器:

  • 定义 map 时需要指明关键字类型又需要指明值类型。
  • 定义 set 时只需要指明关键字类型,因为 set 中没有值。

初始化关联容器:

  • 每个关联容器都定义了一个默认的构造函数,它创建一个指定类型的空容器。
  • 可以将关联容器初始化为另一个同类型的容器的拷贝。
  • 可以从一个值范围来初始化关联容器,这要这些值可以转化为容器所需要的类型就可以。
  • 可以对关联容器进行列表初始化。
map<string, size_t> word_count;     //空容器
//列表初始化
set<string> exclude = { "the","an","a","or","and" };
map<string, string> authors = {
        {"Joyce","James"},
        {"Austen","Jane"},
        {"Dickens","Charles"}
};

初始化 multimap 或 multiset

mapset 中的关键字必须是唯一的,即对于一个给定的关键字,只能有一个元素等于它。multimapmultiset 则没有此限制,它们都允许多个元素具有相同的关键字。

    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.cbegin(), ivec.cend());
    multiset<int> miset(ivec.cbegin(), ivec.cend());

    cout << ivec.size() << endl;    //20
    cout << iset.size() << endl;    //10
    cout << miset.size() << endl;   //20

关键字类型的要求

对于有序容器: mapmultimapset、以及 multiset 关键字类型必须定义元素的比较方法,默认情况下,标准库使用关键字类型的 < 运算符来比较两个关键字。

在集合类型中,关键字就是元素的类型,在映射类型中关键字类型是元素的第一部分的类型。

有序容器的关键字类型

可以提供自定义的操作来代替关键字上的 < 运算符。所提供的操作必须在关键字类型上定义一个严格弱序,可以将严格弱序看作是小于等于。

比较函数应该具备如下性质:

  • 两个关键字不能同时 小于等于对方,如果 k1小于等于 k2 ,那么 k2 决不能小于等于 k1
  • 如果 k1 小于等于 k2,且 k2 小于等于 k3,那么 k1 必须小于等于 k3
  • 如果存在两个关键字,任何一个都不小于等于另一个,那么称这两个关键字是等价的,如果 k1 等价于 k2,且 k2 等价于 k3,那么 k1 必须等价于 k3

如果两个关键字是等价的, 那么容器将它们视为相等来处理,当用作 map 的关键字时,只能有一个元素与这两个关键字关联,可以使用两者中的任意一个来访问对应的值。

使用关键字类型的比较函数

用来组织一个容器中元素的操作的类型也是该容器类型的一部分。为了指定使用自定义的操作,必须在定义关联容器时提供此类型的操作。

bool compareIsbn(const Sales_data &lhs,const Sales_data &rhs)
{
    return lhs.isbn < rhs.isbn;
}

multiset<Sales_data,decltype(compareIsbn)*> bookstore(compareIsbn);

使用 decltype 指出要使用一个给定的函数类型的指针时,需要加上 *

compareIsbn 来初始化 bookstore ,表示向 bookstore 中添加元素时,通过调用 compareIsbn 函数来为这些元素排序。

pair 类型

pair 标准库类型定义在头文件 utility 中。

一个 pair 保存两个数据成员,类似容器,pair 是一个用来生成特定类型的模板,当创建一个 pair 时,必须提供两个类型名,pair 数据成员将具有对应的类型,两个类型不要求一样。

pair<string,string> anon;
pair<string,size_t> word_count;
pair<string,vector> line;

pair 的默认构造函数对数据成员进行值初始化,因此:

  • anon是一个包含两个空 stringpair
  • word_countstring 被初始化为空,size_t 成员则被初始化为0。
  • line 保存了一个空的 string 和一个空的 vector

当然,也可以为每个成员提供初始化器:

pair<string,string> author{"James","Joyce"};

pair 的数据成员是 public 的,两个成员分别命名为 fristsecond
技术图片

创建 pair 对象的函数

想象有一个函数需要返回 pair。在新标准下可以对返回值进行列表初始化:

pairn<string,int> process(vector<string> &v)
{
    if(!v.empty())
        return (v.back(),v.back().size());  //列表初始化
    else
        return pair(string,int);    //隐士构造返回值
}

在较早版本的C++中,不允许使用括号包围的初始化器来返回pair这种类型的对象,必须显示构造返回值:

if(!v.empty())
    return pair<string,int> (v.back(),v.back().size());

还可以使用make_pair来生成pair对象:

if(!v.empty())
    return make_pair(v.back(),v.back().size());

以上是关于关联容器概述的主要内容,如果未能解决你的问题,请参考以下文章

C++/STL0.容器概述

《C++Primer(第5版)》第十一章笔记

Ch5 关联式容器(下)

EF添加关联的提示问题:映射从第 260 行开始的片段时有问题:

片段 XXX 未与片段管理器关联

片段未与片段管理器关联。 (对话片段)