关联容器C++

Posted 扣得君

tags:

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

第11章 关联容器

与顺序容器不同的是,关联容器中的元素是按关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,那么典型的就是我们常见的map与set数据结构

关联容器类型

使用map

map类型通常被称为关联数组

//example1.cpp
#include <iostream>
#include <map>
using namespace std;
int main(int argc, char **argv)

    map<string, size_t> m_map;
    m_map["a"] = 4;
    m_map["b"] = 5;
    cout << m_map["a"] << endl; // 4
    cout << m_map["b"] << endl; // 5
    return 0;

使用set

//example2.cpp
map<string, size_t> m_map;
vector<string> vec = "aaa", "bbb", "ccc", "aaa";
set<string> m_set;
for (auto &item : vec)

    m_set.insert(item);
    cout << item << endl; // aaa bbb ccc aaa
    if (m_map.find(item) != m_map.end())
    
        m_map[item]++;
    
    else
    
        m_map[item] = 1;
    

for (auto &item : m_map)

    // aaa 1 bbb 1 ccc 1
     cout << item.first << " " << item.second << endl;

//遍历set
for (auto &item : m_set)

    cout << item << endl; // aaa bbb ccc

定义关联容器

当定义一个map时,必须指明关键字类型与值类型,而定义set只需指明关键字类型

初始化map与set

空容器、列表初始化、映射键值对列表初始化

//example3.cpp
//空容器
 map<string, size_t> map_1;
//列表初始化
set<string> set_1 = "aaa", "bbb", "ccc", "aaa", "bbbb";
// map列表初始化
 map<string, string> map_2 = 
    "aaa", "vfvdf",
    "bbb", "adfdsfs",
     "ccc", "vfdvdf";

初始化multimap与multiset

multi的意义就是,map一个关键词可以存储多个值,set也可以存储多个相同的值

//example4.cpp
// multiset
vector<string> vec = "aaa", "aaa", "bbb", "bbb", "ccc";
multiset<string> m_set(vec.begin(), vec.end());
for (auto &item : m_set)

    cout << item << " "; // aaa aaa bbb bbb ccc

cout << endl;
cout << m_set.size() << endl; // 5
// multimap
multimap<string, string> m_map = "aaa", "ccc", "aaa", "vvv";
for (auto &item : m_map)

    cout << item.first << " " << item.second << endl;
    // aaa ccc
    // aaa vvv

关键字类型要求

对于有序容器,map、multimap、set、multiset,关键字类型要求必须定义元素比较方法,默认情况下,标准库使用关键字类型的<运算符来比较两个关键字
算法允许自定义比较操作,与之类似也可以提供自定义的操作代替关键字上的<运算符

比较函数必须满足以下条件

  • 两个关键字不能同时“小于等于”对方
  • 如果K1“小于等于”K2,且K2“小于等于”K3,则K1必须“小于等于”K3
  • 如果存在两个关键字,任何一个都不“小于等于”另外一个,则称者是“等价”的,且等价具有传递性

自定义关键字比较函数

形如

  • map<keyType,valueType,函数指针类型>name(函数指针值);
  • set<keyType,函数指针类型>name(函数指针值);
//example5.cpp
struct Person

    int age;
    string name;
;

//关键字比较函数必须满足上面比较函数的条件
bool comparePerson(const Person &a, const Person &b)

    return a.age < b.age && a.name < b.name;


int main(int argc, char **argv)

    // decltype(comparePerson) * 为函数指针
    map<Person, int, bool (*)(const Person &a, const Person &b)> m_map(comparePerson);
    // 或者使用decltype
    // map<Person, int, decltype(comparePerson) *> m_map(comparePerson);
    Person person1;
    person1.age = 19;
    person1.name = "gaowanlu";
    m_map[person1] = 99999;
    auto val = m_map[person1];
    cout << val << endl; // 99999
    return 0;

pair类型

pair的标准库类型,定义在utility头文件中
一个piar保存两个数据成员,类似容器piar是一个用来生成特定类型的模板,大致可以认为是一个键值对

//example6.cpp
//空初始化
pair<string, int> m_pair1;

//列表初始化
pair<int, string> m_pair2999, "gaowanlu";
cout << m_pair2.first << " " << m_pair2.second << endl; // 999 gaowanlu

pair<int, string> m_pair4 = 999, "gaowanlu";
cout << m_pair4.first << " " << m_pair4.second << endl; // 999 gaowanlu

//构造函数初始化
pair<string, int> m_pair3("gaowanlu", 888);
cout << m_pair3.first << " " << m_pair3.second << endl; // gaowanlu 888

//使用make_piar
m_pair4 = make_pair(888, "hello");

//赋值
m_pair4.first = 666;
m_pair4.second = "gaowanlu";
cout << m_pair4.first << " " << m_pair4.second << endl; // 666 gaowanlu

// <、>、<=、>=比较pair
pair<int, int> m_pair5(2, 3);
pair<int, int> m_pair6(4, 3);
//当first与second同时满足才返回true
cout << (m_pair5 < m_pair6) << endl;  // 1
cout << (m_pair5 <= m_pair6) << endl; // 1
cout << (m_pair5 > m_pair6) << endl;  // 0
cout << (m_pair5 >= m_pair6) << endl; // 0

// ==比较pair
m_pair5 = make_pair(4, 3);
cout << (m_pair5 == m_pair6) << endl; // 1

// !=比较piar
cout << (m_pair5 != m_pair6) << endl; // 0

key_type、mapped_type、value_type操作

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

//example7.cpp
#include <iostream>
#include <utility>
#include <set>
#include <map>
using namespace std;
int main(int argc, char **argv)

    // set value_type与key_type
    set<string>::value_type v1; // td::string
    set<string>::key_type v2;   // std::string
    // map key_type value_type mapped_type
    map<string, int>::value_type v3;  // std::pair<const std::string, int>
    map<string, int>::key_type v4;    // std::string
    map<string, int>::mapped_type v5; // int
    return 0;

关联容器迭代器

重点:set迭代器解引用返回const引用,map迭代器解引用返回pair的引用,但pair的first类型是const的,也就是我们只能用迭代器修改second不能修改first

//example8.cpp
set<string> m_set = "aaa", "bbb", "ccc";
map<string, int> m_map = "aaa", 111, "bbb", 222, "ccc", 333;
auto set_iter = m_set.begin(); // std::set<std::string>::iterator
while (set_iter != m_set.end())

    cout << *set_iter++ << endl; // aaa bbb ccc
    // set的迭代器是const的
    //*set_iter = "dscs";//*set_iter返回的是 const string&

auto map_iter = m_map.begin(); // std::map<std::string, int>::iterator
while (map_iter != m_map.end())

    // map_iter->first = "dscs"; //因为解引用返回的是 std::pair<const std::string, int> &
    map_iter->second++;
    cout << map_iter->first << " " << map_iter->second << endl;
    // aaa 112
    // bbb 223
    // ccc 334
    map_iter++;

关联容器和泛型算法

一般不对关联容器使用泛型算法,关键字是const着意味着不能使用修改或重排容器元素的算法,因为这类算法要向元素写入值,而set的元素是const的,map中元素是pair但first是const的

关联容器只用于只读元素的算法,例如泛型算法find查找为顺序查找,而关联容器的特定的find则是进行hash查找,会比泛型算法的find快很多,还可以利用泛型copy算法将元素拷贝

//example9.cpp
map<string, int> m_map = "aaa", 111, "bbb", 222, "ccc", 333;
// copy到vector
vector<pair<string, int>> vec;
copy(m_map.begin(), m_map.end(), back_inserter(vec));
cout << vec.size() << endl; // 3
// copy到新的map
map<string, int> m_map_copy;
copy(m_map.begin(), m_map.end(), inserter(m_map_copy, m_map_copy.end()));
for (auto &item : m_map_copy)

    cout << item.first << " " << item.second << endl;
    // aaa 111
    // bbb 222
    // ccc 333

添加元素

//example10.cpp
map<string, int> m_map;
m_map.insert("hello", 3);
m_map.insert(make_pair("aaa", 6));
m_map.insert(pair<string, int>("bbb", 2));
auto res = m_map.insert(map<string, int>::value_type("ccc", 3));
if (res.second) //插入成功

    map<string, int>::iterator iter = res.first;
    cout << iter->first << " " << iter->second << endl; // ccc 3

m_map.emplace("ddd", 4);                   //背后使用构造函数int(4)
cout << m_map.find("ddd")->second << endl; // 4

set<string> m_set;
m_set.insert("aaa");
m_set.insert("aaa", "bbb", "ccc");
m_set.insert(string("ddd"));
m_set.emplace("hello");       //背后调用构造函数string("hello")
cout << m_set.size() << endl; // 4

向multiset或multimap添加元素

知道二者可以存储多个相同的关键字,insert返回void不像map或者set一样返回一个pair

//example11.cpp
multimap<string, int> m_map;
multiset<string> m_set;
m_map.insert("aaa", 111, "aaa", 222);
m_set.insert("aaa", "ccc", "ccc");
cout << m_map.size() << endl; // 2
cout << m_set.size() << endl; // 3

删除元素

关联容器的erase定义了三个版本

//example12.cpp
//使用关键字
map<string, int> m_map = "aaa", 111, "bbb", 222, "ccc", 333;
set<string> m_set = "aaa", "bbb", "ccc", "ddd";
printMap(m_map); //<aaa,111>  <bbb,222>  <ccc,333>
printSet(m_set); // aaa bbb ccc ddd
size_t count = m_map.erase("aaa");
cout << count << endl; // 1 被删除1个
printMap(m_map);
count = m_set.erase("ccc");
cout << count << endl; // 1
printSet(m_set);

//使用迭代器指定删除的元素位置
m_set.erase(m_set.cbegin());
printSet(m_set); // bbb ddd

//使用迭代器范围
m_set.erase(m_set.cbegin(), m_set.end());
printSet(m_set); //

map的下标操作

map、uordered_map有下标操作,而multimap与unordered_multimap没有下标操作,因为一个关键词可对应多个值

//example13.cpp
map<string, int> m_map = "aaa", 111, "bbb", 222, "ccc", 333;
printMap(m_map); // <aaa,111>  <bbb,222>  <ccc,333>
m_map["aaa"] = 4;
printMap(m_map); // <aaa,4>  <bbb,222>  <ccc,333>

//下标赋值没有的关键字则创建新的元素
m_map["ddd"] = 444;
printMap(m_map); // <aaa,4>  <bbb,222>  <ccc,333>  <ddd,444>

//如果k不再c内,添加一个关键字为k的元素并对值初始化
cout << m_map["eee"] << endl; // 0
printMap(m_map);
// <aaa,4>  <bbb,222>  <ccc,333>  <ddd,444>  <eee,0>

// at方法有检查机制,如果k不在c内则抛出out_of_range异常
int &val = m_map.at("bbb");
cout << val << endl; // 222
try

    m_map.at("fff");

catch (std::out_of_range e)

    // RUNTIME ERROR:: map::at
    cout << "RUNTIME ERROR:: " << e.what() << endl;

find、count、lower_bound、upper_bound、equal_range访问元素

主要为根据关键字查找元素的操作,在multimap与multiset中相同关键字的元素总是相邻存放

//example14.cpp
multimap<int, string> m_map111, "aaa", 222, "bbb", 444, "ddd", 222, "ccc";
printMap(m_map); // <111,aaa>  <222,bbb>  <222,ccc>  <444,ddd>
    
// count方法
cout << m_map.count(222) << endl; // 2

// find方法
auto res = m_map.find(222);
int size = 0, count = m_map.count(222);
while (size < count && res != m_map.cend())

    //<222,bbb> <222,ccc>
    cout <<

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

C++顺序容器知识总结

c++基础——关联容器

关联容器

顺序容器

关联容器

C++ STL容器的选择