【知识讲解】 C++容器map和set的介绍以及使用


目录

前言

[Part1. C++容器的分类](#Part1. C++容器的分类)

[Part2. set介绍及使用](#Part2. set介绍及使用)

[Part2.1. 基本构成](#Part2.1. 基本构成)

[Part2.2. 比较器相关小知识](#Part2.2. 比较器相关小知识)

[Part2.3. 插入函数与构造函数](#Part2.3. 插入函数与构造函数)

[Part2.4. 核心接口的使用](#Part2.4. 核心接口的使用)

[Part2.5. multiset 与 set 在函数上的区别](#Part2.5. multiset 与 set 在函数上的区别)

[Part2.6. set的使用](#Part2.6. set的使用)

[Part3. map介绍及使用](#Part3. map介绍及使用)

[Part3.1. 基本构成](#Part3.1. 基本构成)

[Part3.2. 插入函数与构造函数](#Part3.2. 插入函数与构造函数)

[Part3.3. 键重复规则](#Part3.3. 键重复规则)

[Part4. 结语](#Part4. 结语)


前言

map和set作为C++很重要的容器,了解他们是很必要的。接下来,跟随小编的视角来看看这两个容器的介绍和基本的使用吧。


let's go!!!!!!!!!


Part1. C++容器的分类

C++有着许许多多的容器,大致的根据其存储的数据之间的关系可以分为两类,即:

<1> 序列式容器

主要特征:数据之间没有关联,仅仅是有序存放。
代表:string、vector、list、array

<2> 关联式容器

主要特征:数据与数据之间存在关联(例如二叉树中的父子关系)。

代表:map、set


Part2. set介绍及使用

Part2.1. 基本构成

<1> Set的模板参数为这三个元素:template <class T, class compare = less<T>, class Alloc>(存放元素的类型、比较器(仿函数)、空间配置器)

<2> 同时其增删查的时间复杂度:O(logN)(高度次)

<3> 迭代器类型:双向迭代器,支持++、--。

<4> 限制:不支持直接修改元素值,修改会破坏二叉搜索树的有序性。如果要修改,只能先删除旧值,再插入新值。


Part2.2. 比较器相关小知识

<1> 基本知识:默认比较器 less<T>:左 < 右,从小到大升序排列。如果传入 greater<int>,则变为从大到小降序。

<2> 但是通常比较器只有<比较函数,如何实现>逻辑?由于a > b 等价于 b < a,只需要把两个参数交换位置调用比较函数即可(a>b <=> less<>(b,a))。


Part2.3. 插入函数与构造函数

cpp 复制代码
set<int> s;
s.insert({1,2,4});
set<int> a={1,2,3};
set<int> b({2,3,2});//构造函数调用insert进行列表初始化

Part2.4. 核心接口的使用

<1> find(x) 找到元素则返回对应迭代器,找不到返回end() 。

<2> erase(x) 可以传入迭代器或者元素值。传入值时会删除所有匹配元素,返回成功删除的元素个数。

<3> count(x) 返回元素的个数,在set中结果只能是0或1,常用于判断元素是否存在。

<4> lower_bound(val) 返回第一个 ≥ val 元素的迭代器

<5> upper_bound(val) 返回第一个 > val 元素的迭代器

<6> lower_bound(val)和upper_bound(val)的应用:

cpp 复制代码
//删除区间 [30, 50] 内所有元素:
set<int>::iterator left = st.lower_bound(30);
auto right = st.upper_bound(50);
st.erase(left, right);
//为什么右端要用upper_bound?因为erase是左闭右开区间[left, right),使用upper_bound才能把等于50的元素一并删掉。

Part2.5. multiset 与 set 在函数上的区别

<1> 由于multiset中会有重复的元素。对于这种情况,find函数会返回在中序遍历中第一个出现的元素的迭代器。

<2> 具体实现的思路是:找到了元素就继续往它的左子树中去找,直到找到nullptr结束,返回这个过程之最后遇到的元素的迭代器。


Part2.6. set的使用


cpp 复制代码
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        set<ListNode*> aaa;
        while(head!=nullptr)
        {
            if(aaa.count(head)==0)//如果检测到set中有这个元素 就说明这是第一个重复的元素 也就是链表环的起点 用set关键在于把检测是否存在的时间复杂度降为O(logN)
            {
                aaa.insert(head);
                head=head->next;
            }
            else
            {
                break;
            }
        }
        return head;
    }
};

题目链接:142. 环形链表 II - 力扣(LeetCode)


cpp 复制代码
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        set<int> s1;
        for(auto i:nums1)
        {
            s1.insert(i);//初始化S1
        }
        set<int> s2;
        for(auto i:nums2)
        {
            s2.insert(i);
        }
        vector<int> ans;
        set<int>::iterator it1=s1.begin();
        auto it2=s2.begin();
        while(it1!=s1.end()&&it2!=s2.end())
        {
            if(*it1==*it2)
            {
                ans.push_back(*it1);
                it1++;
                it2++;
            }
            else if(*it1<*it2)//由于set遍历为中序遍历 有序 就像合并两个有序数组一样 小的先走
            {
                it1++;
            }
            else
            {
                it2++;
            }
        }
        return ans;
    }
};

题目链接:349. 两个数组的交集 - 力扣(LeetCode)


交差补集在现实中的应用:云端数据与本机数据的同步。


Part3. map介绍及使用

Part3.1. 基本构成

<1> template <class Key, class Value, class Compare, class Alloc>(同set)

<2> 存储单元:pair<const Key, T>。其中他的两个成员,first:对应键key,const 不可修改。second:对应值value,允许修改。

cpp 复制代码
map<int, int>::iterator it = mp.begin();
cout << it->first << endl;   // 获取key
cout << it->second << endl;  // 获取value

Part3.2. 插入函数与构造函数

cpp 复制代码
map<string, string> mp;
<1> 
pair<string, string> k = {"aaa", "bbb"};//实例化对象插入
mp.insert(k);

<2>
mp.insert(make_pair("aaa", "bbb"));//临时对象插入

<3>
mp.insert({"aaa", "bbb"});//C++11

构造函数另一种用法:map<string, string> mp = {{"name", "zhangsan"},{"age", "20"}};//与插入函数结合

Part3.3. 键重复规则

当插入key相同、value不同的数据时:insert不会覆盖原有旧数据,新键值对直接插入失败。可以通过it->second直接修改value。


Part4. 结语

上面我们介绍了set和map的介绍和基本使用,接下来小编还会有更多文章关于这两个的,也请敬请期待~
最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!

最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~