【C++学习笔记】:map 容器

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: map类属于关联式容器,可用于存储和检索集合中的数据元素...

1、写在前面

大家好,今天文章的内容是:

  • map容器

2、内容

2.1、介绍

map类属于关联式容器,可用于存储检索集合中的数据元素。

备注:

  • 集合中的每个数据元素均为一种映射关系,是一种包含键和数据值的元素对。简单来说,每个map元素都是一个键值对;
  • 键具有唯一性,在map中不能出现重复的键,每个键都是独一无二的;
  • 键是常量,无法修改,我们只能修改键对应的数据值;

2.2、map类

(1) 语法

map类的语法如下:

template <class Key,
    class T,
    class Traits = less<Key>,
    class Allocator = allocator<pair <const Key, T>>>
class map;

(2) 参数

Key

Key 指的是在map中存储的键的数据类型

T

T 指的是map中键对应的元素值的数据类型

Traits

Traits 是一种提供函数对象的类型,该函数对象将两个元素值作为排序键进行比较,用于指定map中的排序规则;

备注:

  • Traits 属于可选参数
  • 默认值为less<key>,即升序。
  • 也可以设置为greater<key>,即降序。

Allocator

Allocator 是一种表示分配器对象的类型。

备注:

  • Allocator 是可选参数
  • 默认值为allocator<pair<const Key, T> >
  • 该分配器对象封装了有关映射map的内存分配和解除分配的详细信息。

(3) 元素

在使用map之前,我们需要清楚,map中的每个元素,其数据类型是什么?

来看看map中元素的定义语句:

typedef pair<const Key, T> value_type;

也就是说,map中存储的元素,其数据类型就是value_type

map容器存储的元素都是pair对象,其利用了pair类来创建键值对,其中各个键值对的键和值都可以是任意数据类型,包括C++基本数据类型(如intdouble等)、结构体或自定义类等。


2.3、创建map容器

(1) 导入头文件

因为map容器定义在<map>头文件中,并位于std命名空间中。

所以我们在使用map容器之前需要导入以下代码:

#include <map>
using namespace std;

在导入头文件后,就可以使用map容器了。


(2) 举例一

代码:

map <int, int> m1;

上述代码创建了一个空的map容器m1。此时容器中是没有存储任何键值对的。其中键key和值value的数据类型都是int类型,并且使用了默认的排序规则(升序:less<Key


(3) 举例二

下面的程序创建了一个空map容器,并向其中插入了五个元素。每个元素的数据类型都是pair<int, int>

输出map中的内容后,可以发现,虽然在插入数据元素时键是无序的,但是在map内部会自动按照指定的键比较函数来按顺序排列键。这里使用的是默认值less<key>,即升序。

代码:

#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;

void printMap(const map<int, int>& m) {
    cout << "容器中的内容为:" << endl;
    cout << "key\tvalue" << endl;
    for (auto i : m) {
        cout << i.first << "\t" << i.second << endl;
    }
}

int main() {
    // 创建一个空容器 m2 
    map <int, int> m2;
    // 插入五个元素 
    m2.insert(myPair(5, 55));
    m2.insert(myPair(1, 11));
    m2.insert(myPair(3, 33));
    m2.insert(myPair(2, 22));
    m2.insert(myPair(4, 44));
    // 输出
    cout << "m2"; 
    printMap(m2); 
    return 0;
} 

运行结果:

m2容器中的内容为:
key     value
1       11
2       22
3       33
4       44
5       55

(4) 举例三

创建一个map容器并复制其他map容器中的内容。

代码:

#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;

void printMap(const map<int, int>& m) {
    cout << "容器中的内容为:" << endl;
    cout << "key\tvalue" << endl;
    for (auto i : m) {
        cout << i.first << "\t" << i.second << endl;
    }
}

int main() {
    // 创建一个空容器 m1 
    map <int, int> m1;
    // 插入五个元素 
    m1.insert(myPair(5, 55));
    m1.insert(myPair(1, 11));
    m1.insert(myPair(3, 33));
    m1.insert(myPair(2, 22));
    m1.insert(myPair(4, 44));
    
    // 创建一个容器 m3 并用 m2 进行初始化 
    map<int, int> m3(m1);
    
    // 输出
    cout << "m3";
    printMap(m3); 
    return 0;
} 

运行结果:

m3容器中的内容为:
key     value
1       11
2       22
3       33
4       44
5       55

(5) 举例四

创建一个map容器并用其他map容器中指定区间上的元素来初始化。

代码:

#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;

void printMap(const map<int, int>& m) {
    cout << "容器中的内容为:" << endl;
    cout << "key\tvalue" << endl;
    for (auto i : m) {
        cout << i.first << "\t" << i.second << endl;
    }
}

int main() {
    // 创建一个空容器 m1 
    map <int, int> m1;
    // 插入五个元素 
    m1.insert(myPair(5, 55));
    m1.insert(myPair(1, 11));
    m1.insert(myPair(3, 33));
    m1.insert(myPair(2, 22));
    m1.insert(myPair(4, 44));
    // 输出
    cout << "m1"; 
    printMap(m1);
    
    cout << "\n取m1中指定区间 [1, 3) 内的元素来初始化 m4\n" << endl; 

    
    // 创建两个迭代器对象
    map<int, int>::const_iterator first, last;
    // first指向 m1 的第一个元素
    first = m1.begin();
    // last 指向 m1 的第三个元素
    last = m1.begin();
    last++;
    last++;
    // 创建新容器 m4并 用原先的容器 m1 中指定的区间来初始化 m4
    map <int, int> m4(first, last);
    // 输出
    cout << "m4"; 
    printMap(m4); 
    return 0;
} 

运行结果:

m1容器中的内容为:
key     value
1       11
2       22
3       33
4       44
5       55

取m1中指定区间 [1, 3) 内的元素来初始化 m4

m4容器中的内容为:
key     value
1       11
2       22

(6) 举例五

创建并初始化map容器。

代码:

#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;

void printMap(const map<int, int>& m) {
    cout << "容器中的内容为:" << endl;
    cout << "key\tvalue" << endl;
    for (auto i : m) {
        cout << i.first << "\t" << i.second << endl;
    }
}

int main() {
    // 创建容器 m5 并初始化 
    map <int, int> m5{{3, 33}, {1, 11}, {2, 22}};
    // 输出
    cout << "m5"; 
    printMap(m5);
    return 0;
} 

运行结果:

m5容器中的内容为:
key     value
1       11
2       22
3       33

2.4、成员函数

map的成员函数有很多,这里记录几个常用的。

at

  • at()函数用于查找给定键所对应的元素值

语法如下:

T& at(const Key& key);
const T& at(const Key& key) const;

举个例子:

#include <iostream>
#include <map>
using namespace std;

void printMap(const map<char, int>& m) {
    cout << "容器中的内容为:" << endl;
    cout << "key\tvalue" << endl;
    for (auto i : m) {
        cout << i.first << "\t" << i.second<< endl;
    }
    cout << '\n';
}

int main() {
    map<char, int> myMap{ {'b',76}, {'a', 98}, {'c', 59} };
    cout << "myMap";
    printMap(myMap);
    cout << "myMap.at('a') == " << myMap.at('a') << '\n' << endl;
    cout << "myMap.at('b') == " << myMap.at('b') << '\n' << endl;
    cout << "myMap.at('c') == " << myMap.at('c') << '\n' << endl;

    return (0);
}

运行结果:

myMap容器中的内容为:
key     value
a       98
b       76
c       59

myMap.at('a') == 98

myMap.at('b') == 76

myMap.at('c') == 59

begin

begin()函数用于返回一个迭代器对象,其指向map中的第一个元素。

语法如下:

iterator begin();
const_iterator begin() const;

举个例子:

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, int> m;
    m.insert ( pair<int, int>( 1, 100 ) );
    m.insert ( pair<int, int>( 2, 200 ) );
    m.insert ( pair<int, int>( 3, 300 ) );
    map<int, int>::iterator m_it = m.begin();
    cout << "map中的第一个键为:" << m_it->first << ",其对应的值为:" << m_it->second << endl;
    m_it++;
    m_it++;
    cout << "map中的第三个键为:" << m_it->first << ",其对应的值为:" << m_it->second << endl;
    return (0);
}

运行结果:

map中的第一个键为:1,其对应的值为:100
map中的第三个键为:3,其对应的值为:300

end

end()函数用于返回末尾元素之后的迭代器对象。

注意,返回的双向迭代器是指向容器最后一个元素的后一个位置。

备注:

如果映射为空,则map::end() == map::begin()


clear

clear()函数用于清除map中的所有元素。

语法如下:

void clear();

contains

contains()函数用于判断map中是否含有指定键的元素。如果找到该元素,则返回true,否则返回false

备注:

  • 使用需知,contains()属于C++20中新增的功能。

语法如下:

bool contains(const Key& key) const;
template<class K> bool contains(const K& key) const;

emplace

emplace()函数可用于向map内插入构造的元素,不执行复制操作或移动操作。

语法如下:

template <class... Args>
pair<iterator, bool> emplace(Args&&... args);

说明:

  • 这个函数的返回值是:pair<iterator, bool>,假设返回的是pr
  • 如果新元素插入成功,则pr.second,即bool值为true
  • 如果新元素插入失败,则pr.second,即bool值为false。什么情况下会插入失败?如果插入的元素的键keymap中已经存在了,那么此时插入操作返回值的bool值为false
  • pr.first则是一个迭代器对象。如果bool值为true,则该迭代器对象pr.first指向的是新插入的元素。如果bool值为false,则该迭代器对象pr.first指向的是现有的元素。

举个例子:

#include <iostream>
#include <map>
#include <string>
using namespace std;

template <typename M> void print(const M& m) {
    cout << "容器内容为:\nkey\tvalue\n";
    for (const auto& i : m) {
        cout << i.first << '\t' << i.second << endl;
    }
    cout << endl;
}

template <typename T> void judge(const T& e) {
    cout << "正在修改map..."; 
    if ( e.second == true){
        cout << "修改成功!" << endl;
    }
    else{
        // 解引用,获取该迭代器对象 e 指向的 map 元素 
        auto p = *e.first;    
        cout << "添加元素失败!\n"
             << "欲添加的元素中,键值(" << p.first << ")已经存在了" << endl; 
    }
    cout << endl;
}
int main() {
    map <int, string> m1{{3, "叁"}, {1, "壹"}, {2, "贰"}};
    print(m1); 
    auto re = m1.emplace(4, "肆");
    judge(re);
    print(m1); 
    re = m1.emplace(4, "四");
    judge(re);
    print(m1); 
    return 0; 
}

运行结果:

容器内容为:
key     value
1       壹
2       贰
3       叁

正在修改map...修改成功!

容器内容为:
key     value
1       壹
2       贰
3       叁
4       肆

正在修改map...添加元素失败!
欲添加的元素中,键值(4)已经存在了

容器内容为:
key     value
1       壹
2       贰
3       叁
4       肆

empty

empty()函数用于判断该map容器是否为空。如果map为空,则返回true,否则返回false

语法如下:

bool empty() const;

erase

erase()函数用于从map中的指定位置删除单个元素,或删除指定范围内的元素,或者删除与指定键匹配的map元素。

语法如下:

iterator erase(const_iterator Where);
iterator erase(const_iterator First, const_iterator Last);
size_type erase(const key_type& Key);

举个例子:

#include <iostream>
#include <map>
#include <string>
using namespace std;

template <typename M> void print(const M& m) {
    cout << "容器内容为:\nkey\tvalue\n";
    for (const auto& i : m) {
        cout << i.first << '\t' << i.second << endl;
    }
    cout << endl;
}

int main() {
    // 创建四个容器
    map<int, string> m0{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
    map<int, string> m1{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
    map<int, string> m2{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
    map<int, string> m3{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
    cout << "原先的";
    print(m0); 
    
    // 1. 调用 erase(const_iterator Where) 
    m1.erase(m1.begin());
    cout << "删除第一个元素后,"; 
    print(m1);
    
    // 2. 调用 erase(const_iterator First, const_iterator Last);
    map<int, string>::const_iterator first = m2.begin();
    map<int, string>::const_iterator last = m2.begin();
    last++;
    last++;
    m2.erase(first, last);
    cout << "删除指定区间[1, 3)内的元素后,";
    print(m2);
    
    // 3. 调用 erase(const key_type& Key)
    m3.erase(3);
    cout << "删除指定键为3的元素后,"; 
    print(m3);
    
    return 0;
}

运行结果:

原先的容器内容为:
key     value
1       A
2       B
3       C
4       D
5       E

删除第一个元素后,容器内容为:
key     value
2       B
3       C
4       D
5       E

删除指定区间[1, 3)内的元素后,容器内容为:
key     value
3       C
4       D
5       E

删除指定键为3的元素后,容器内容为:
key     value
1       A
2       B
4       D
5       E

find

find()函数可用于查找与给定键匹配的元素。

语法如下:

iterator find(const Key& key);
const_iterator find(const Key& key) const;

说明:

  • 如果找到和给定的键匹配的元素,则返回的迭代器对象会指向该元素。
  • 但如果在map中找不到与键匹配的元素,则返回的迭代器对象指向的位置和map::end()指向的位置是一样的。

举个例子:

#include <iostream>
#include <map>
using namespace std;

template <typename M> void print(const M& m) {
    cout << "容器内容为:\nkey\tvalue\n";
    for (const auto& i : m) {
        cout << i.first << '\t' << i.second << endl;
    }
    cout << endl;
}

template <typename M> void findVal(const M& m, int& value) {
    if(m.find(value) == m.end()) {
        cout << "查找失败!找不到键为 " << value << " 的元素" << '\n'  << endl;
    } else {
        cout << "找到了!容器里键为 " << value << " 的元素对应的值为 " << m.at(value) << '\n' << endl; 
    }
}

int main() {
    // 创建四个容器
    map<int, char> m{{1, 'A'}, {4, 'D'}, {2, 'B'}, {5, 'E'}, {3, 'C'}};
    print(m);
    int v1 = 4;
    int v2 = 6;
    findVal(m, v1);
    findVal(m, v2);
    return 0;
}

运行结果:

容器内容为:
key     value
1       A
2       B
3       C
4       D
5       E

找到了!容器里键为 4 的元素对应的值为 D

查找失败!找不到键为 6 的元素

size

size()函数用于返回map中的元素数量。

语法如下:

size_type size() const;

2.5、小结

有关map的小结:

  • map是一种大小可变的关联式容器,其中存储的每个元素都包含一个映射关系,可用来基于关联键高效的检索对应的元素值。
  • map提供了双向迭代器来访问其元素;并且在map中,元素值根据指定的比较函数按键值排序。
  • 另外,map中的元素都具有唯一的键与其对应,每个键都是独一无二的。

3、写在最后

好了,文章的内容就到这里,感谢观看。

目录
相关文章
|
1月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
48 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
1月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
52 5
|
1月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
53 2
|
3月前
|
C++ 容器
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——AVL树
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——AVL树
32 5
|
3月前
|
存储 C++ 索引
|
3月前
|
容器
【Qt 学习笔记】Qt常用控件 | 容器类控件 | Tab Widget的使用及说明
【Qt 学习笔记】Qt常用控件 | 容器类控件 | Tab Widget的使用及说明
87 2
|
3月前
|
安全 编译器 容器
C++STL容器和智能指针
C++STL容器和智能指针
|
3月前
|
C++ 容器
C++中自定义结构体或类作为关联容器的键
C++中自定义结构体或类作为关联容器的键
40 0
|
3月前
|
存储 缓存 NoSQL
【C++】哈希容器
【C++】哈希容器
|
3月前
|
关系型数据库 C++ 容器
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——红黑树
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——红黑树
35 0