C++ map 和 set 使用详解

Python爬虫实战:绕过B站-352风控的完整解决方案 网络爬虫技术是数据采集和自动化测试的重要工具,其核心原理是通过模拟HTTP请求获取网页数据。在实践过程中,开发者常会遇到网站反爬机制,这涉及请求指纹识别、IP行为分析等安全技术。这些风控措施的价值在于保护网站数据安全和服务器资源,广泛应用于电商、社交、内容平台等场景。针对B站等平台的-352风控错误,需要综合运用请求头伪装、会话管理、参数签名破解等技术方案。本文重点探讨如何通过构建完整的浏览器级请求头、管理Cookie会话、以及使用Playwright等浏览器自动化工具,有效解决Python爬虫在B站数据采 阅读详情

目录


一、为什么你需要 map 和 set?

回想一下你初学编程时写过的"查找"代码:一个数组,一个 for 循环,最坏情况下需要把所有元素遍历一遍。数据量小的时候还行,当数据涨到百万级别,使用O(N) 复杂度的算法显然不够明智。

C++ STL 给我们提供了一类专门的关联式容器——map 和 set。不同于 vector、list 这些序列式容器,它们内部基于平衡二叉搜索树(红黑树)组织数据,查找、插入、删除的时间复杂度都是 O(logN),而且元素天然有序。

它们的“分工”方式是:

  • set:只存 key,自动去重 + 排序
  • map:存 key-value 对,key 唯一,按 key 排序

这篇文章会带你从基础操作一步步走到 LeetCode 实战,把这两个容器吃透。


二、set——自动排序的去重集合

2.1 模板参数一览

先看一眼 set 的模板声明,这能帮你理解它的设计哲学:

template < class T,                       // 键的类型
           class Compare = less<T>,        // 比较器,默认升序
           class Alloc = allocator<T>      // 空间配置器
         > class set;

T 既是 key_type 也是 value_type——在 set 里,key 就是 value,value 就是 key,二者合一。

2.2 第一个例子:插入 + 遍历

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

int main()
{
    // 默认升序排列
    set<int> s;
    s.insert(5);
    s.insert(2);
    s.insert(7);
    s.insert(5);  // 重复的 5
    s.insert(7);  // 重复的 7
    s.insert(3);

    auto it = s.begin();
    while (it != s.end())
    {
        // *it = 1;  // 编译错误!不能修改 set 中的元素
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    // 输出:2 3 5 7

    return 0;
}

即使插入了 6 次,最终只保留了 4 个元素,而且从小到大排好了序。这就是 set 的两个核心特性:去重 + 升序排序。

这里有个值得留意的细节:set 的迭代器是指向 const value_type 的,也就是你不能通过迭代器去修改元素的值。试想一下,如果你偷偷把 *it 改成了一个别的值,整棵红黑树的排序结构就会被破坏。

2.3 改排序规则:降序 set

如果你想让元素从大到小排列,换一个比较器即可:

set<int, greater<int>> s;
s.insert(5);
s.insert(2);
s.insert(7);
s.insert(5);
s.insert(3);

for (auto e : s)
    cout << e << " ";
cout << endl;
// 输出:7 5 3 2

greater<int> 是 STL 内置的仿函数。你也可以自己写一个比较器,实现任意自定义排序——比如对某个结构体按特定字段排序。

2.4 构造函数:多种初始化方式

set 提供了多种构造方式:

// 方式一:构造空 set,再逐个插入
set<int> s1;
s1.insert(5);
s1.insert(2);

// 方式二:用迭代器区间构造
int arr[] = {4, 2, 7, 2, 8, 5, 9};
set<int> s2(arr, arr + 7);

// 方式三:拷贝构造
set<int> s3(s2);

// 方式四:initializer_list(C++11,最推荐)
set<int> s4 = {4, 2, 7, 8, 5, 9};

// string 的 set——按 ASCII 排序
set<string> strset = {"sort", "insert", "add"};
for (auto& e : strset)
    cout << e << " ";
cout << endl;
// 输出:add insert sort

2.5 insert 详解:单个插入和批量插入

set<int> s = {4, 2, 7};

// 单个插入:返回 pair<iterator, bool>
//   iterator 指向插入位置(或已存在元素的位置)
//   bool 表示是否插入成功
auto ret = s.insert(5);

// 批量插入:传入 initializer_list
s.insert({2, 8, 3, 9, 2});  // 重复的 2 不会被再次插入

for (auto e : s)
    cout << e << " ";
cout << endl;
// 输出:2 3 4 5 7 8 9

注意,insert 返回值是一个 pair<iterator, bool>,在后面讲 operator[] 的时候要考。

2.6 erase:删除的三种方式

set<int> s = {4, 2, 7, 2, 8, 5, 9};
// 此时 s 中:2 4 5 7 8 9

// 方式一:通过迭代器删除(删除最小值)
s.erase(s.begin());
// 剩余:4 5 7 8 9

// 方式二:直接按值删除,返回删除个数(0 或 1)
int x;
cin >> x;
int num = s.erase(x);
if (num == 0)
    cout << x << "不存在!" << endl;
else
    cout << x << "删除成功!" << endl;

// 方式三:先 find,再按迭代器删除
cin >> x;
auto pos = s.find(x);
if (pos != s.end())
{
    s.erase(pos);  // 删除后 pos 失效,不要再使用
}
else
{
    cout << x << "不存在!" << endl;
}

一个易错点:erase(pos) 之后 pos 就失效了,不要尝试解引用它。

2.7 find 和 count:O(logN) vs O(N)

这是新同学很容易忽视的性能差异:

set<int> s = {4, 2, 7, 2, 8, 5, 9};

int x = 7;

// 算法库的 find —— 通用算法,线性遍历,O(N)
auto pos1 = find(s.begin(), s.end(), x);

// set 自己的 find —— 利用红黑树结构查找,O(logN)
auto pos2 = s.find(x);

100 万元素时,std::find 最坏要比较 100 万次,而 set::find 只需约 20 次。

相比之下,count(x) 更适合只关心"存在与否"的场景:

cin >> x;
if (s.count(x))
    cout << x << "在!" << endl;
else
    cout << x << "不存在!" << endl;

set 中 count 的返回值只能是 0 或 1,天然适合做布尔判断,可以用来快速查找。

2.8 lower_bound 和 upper_bound:精确定位区间

这对接口是 set 的进阶武器:

  • lower_bound(x):返回第一个 >= x 的元素位置
  • upper_bound(x):返回第一个 > x 的元素位置
set<int> myset;
for (int i = 1; i < 10; i++)
    myset.insert(i * 10);  // 10 20 30 40 50 60 70 80 90

// 删除 [30, 60] 范围内的元素
auto itlow = myset.lower_bound(30);  // 第一个 >= 30 → 指向 30
auto itup  = myset.upper_bound(60);  // 第一个 > 60  → 指向 70

// 左闭右开区间:[itlow, itup),删除 30 40 50 60
myset.erase(itlow, itup);

for (auto e : myset)
    cout << e << " ";
cout << endl;
// 输出:10 20 70 80 90

区间删除、范围查询等场景中,lower_bound + upper_bound 一对组合拳下来非常高效。


三、multiset——排序但不做去重

有时候我们既要排序,又不想丢失重复数据,multiset 正好填补这个空缺。

3.1 和 set 的核心差异

multiset<int> s = {4, 2, 7, 2, 4, 8, 4, 5, 4, 9};
// 输出:2 2 4 4 4 4 5 7 8 9

元素有序,但重复值全部保留。三个接口的行为随之变化:

操作setmultiset
find(x)返回 x 的位置返回中序遍历第一个 x 的位置
count(x)0 或 1实际出现次数
erase(x)最多删 1 个删除所有等于 x 的元素

3.2 遍历重复元素

multiset<int> s = {4, 2, 7, 2, 4, 8, 4, 5, 4, 9};

int x;
cin >> x;
auto pos = s.find(x);
while (pos != s.end() && *pos == x)
{
    cout << *pos << " ";
    ++pos;
}
cout << endl;

cout << s.count(x) << endl;  // 返回 x 的实际个数

s.erase(x);  // 删除所有 x

如果你只想删除其中某一个,应该用迭代器方式:s.erase(s.find(x))。


四、实战一:用 set 解 LeetCode 经典题

4.1 LeetCode 349——两个数组的交集

题目:给定两个数组,返回它们的交集(结果中去掉重复元素)。

思路很直接:把两个数组分别扔进 set(自动去重 + 排序),然后用双指针同时遍历两个有序集合,相等的元素就是交集。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        set<int> s1(nums1.begin(), nums1.end());
        set<int> s2(nums2.begin(), nums2.end());

        vector<int> ret;
        auto it1 = s1.begin();
        auto it2 = s2.begin();
        while (it1 != s1.end() && it2 != s2.end())
        {
            if (*it1 < *it2)
                it1++;
            else if (*it1 > *it2)
                it2++;
            else
            {
                ret.push_back(*it1);
                it1++;
                it2++;
            }
        }
        return ret;
    }
};

这题的精妙之处在于,set 同时解决了去重和排序两个问题,让后续的双指针遍历变得非常优雅。两个有序序列求交集,就像翻两本按字典序排好的书页,谁小谁翻页,一样就记录——时间复杂度 O(N+M)。

4.2 LeetCode 142——环形链表 II

题目:给定一个链表,判断是否有环,若有环返回环的入口节点。

经典的快慢指针解法能办到 O(1) 空间,但如果一时间想不起来,用 set 也能写出直观又清晰的解法:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        set<ListNode*> s;
        ListNode* cur = head;
        while (cur)
        {
            auto ret = s.insert(cur);
            if (ret.second == false)  // 插入失败说明 cur 已经出现过
                return cur;            // 这就是环的入口
            cur = cur->next;
        }
        return nullptr;
    }
};

这里利用 insert 返回值的 second 判断节点是否第一次出现:每个节点指针如果是第一次出现插入成功,是第二次出现说明有环。虽然不是最优解法,但胜在思路清晰、不易出错,笔试时能快速拿到分数。


五、map——键值对的红黑树字典

如果说 set 是"一堆有序的钥匙",那 map 就是"一把钥匙配一个箱子的管理库"——每个 key(键)映射到一个 value(值),底层同样是红黑树,按 key 排序。

5.1 模板参数一览

template < class Key,                        // 键的类型
           class T,                          // 值的类型
           class Compare = less<Key>,        // 比较器
           class Alloc = allocator<pair<const Key, T>>
         > class map;

注意 value_type 是 pair<const Key, T>——key 自带 const 属性,天然不可修改。

5.2 pair 是什么?

在接触 map 之前,有必要先认识一下 pair——它是 map 中存储数据的基本单元:

template <class T1, class T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;

    T1 first;
    T2 second;

    pair() : first(T1()), second(T2()) {}
    pair(const T1& a, const T2& b) : first(a), second(b) {}

    template<class U, class V>
    pair(const pair<U,V>& pr) : first(pr.first), second(pr.second) {}
};

结构很简单——两个成员 first 和 second,支持默认构造、参数构造和拷贝构造。C++ 还提供了 make_pair 函数模板,帮你自动推导类型:

template <class T1, class T2>
inline pair<T1, T2> make_pair(T1 x, T2 y)
{
    return pair<T1, T2>(x, y);
}

5.3 map 的插入:四种方式

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

int main()
{
    // 构造时用 initializer_list 初始化
    map<string, string> dict = {
        {"left", "左边"}, {"right", "右边"},
        {"insert", "插入"}, {"string", "字符串"}
    };

    // 方式一:显式构造 pair 对象再插入
    pair<string, string> kv1("first", "第一个");
    dict.insert(kv1);

    // 方式二:匿名 pair 对象
    dict.insert(pair<string, string>("second", "第二个"));

    // 方式三:make_pair(自动类型推导,推荐)
    dict.insert(make_pair("sort", "排序"));

    // 方式四:C++11 花括号(最简洁,最推荐)
    dict.insert({"auto", "自动的"});

    // key 重复时,insert 不会覆盖
    dict.insert({"auto", "自动的xxxx"});
    // "auto" 对应的值仍然是 "自动的"
}

四种方式功能等价,可读性上 {"key", "value"} 最干净利落。

insert 的返回值是 pair<iterator, bool>:

  • first(iterator):指向插入元素(或已存在元素)的迭代器
  • second(bool):true 表示插入成功,false 表示 key 已存在

5.4 遍历 map

map<string, string> dict = {
    {"left", "左边"}, {"right", "右边"},
    {"insert", "插入"}, {"string", "字符串"}
};
dict.insert({"auto", "自动的"});

auto it = dict.begin();
while (it != dict.end())
{
    // it->first   是 key(const,不可修改)
    // it->second  是 value(可以修改)

    // it->first += 'x';  // 编译报错!
    it->second += 'x';    // 修改 value 没问题

    cout << it->first << ":" << it->second << endl;
    ++it;
}

输出按 key 的字典序排列:

auto:自动的x
first:第一个x
insert:插入x
left:左边x
right:右边x
second:第二个x
sort:排序x
string:字符串x

关于 it->first 的写法:迭代器指向的是 pair 对象,it->first 本质上是 (*it).first 的语法糖。编译器生成的 operator-> 返回的是 pair* 的指针,再通过 -> 访问其成员。这个链式调用 C++ 会在编译期帮你展开。

5.5 用 map 做个简易词典

map<string, string> dict = {
    {"left", "左边"}, {"right", "右边"},
    {"insert", "插入"}, {"string", "字符串"}
};

string str;
while (cin >> str)
{
    auto ret = dict.find(str);
    if (ret != dict.end())
        cout << "->" << ret->second << endl;
    else
        cout << "词库中未收录" << endl;
}

输入 left 输出 ->左边,输入 hello 输出 词库中未收录。一个极简的词典就成型了


六、operator[]——map 最强大也最容易踩坑的接口

6.1 operator[] 的内部实现

map 的 operator[] 既是查找接口,也是插入接口。它的源码等价于:

mapped_type& operator[] (const key_type& k)
{
    // 1. 调用 insert({k, mapped_type()})
    //    mapped_type() 是 value 类型的默认值(int 是 0,string 是 "")
    // 2. insert 返回 pair<iterator, bool>
    //    - 如果 k 不存在,插入 {k, 默认值},bool 为 true
    //    - 如果 k 已存在,什么也不做,bool 为 false
    // 3. 不管存不存在,最终都返回 it->second 的引用
    pair<iterator, bool> ret = insert({ k, mapped_type() });
    iterator it = ret.first;
    return it->second;
}

关键信息提炼:

  • key 不存在:插入一个默认 value,然后返回这个 value 的引用
  • key 存在:直接返回已有 value 的引用

6.2 operator[] 的三种用途

map<string, string> dict;
dict.insert(make_pair("sort", "排序"));

// 用法一:插入(key 不存在时插入默认值)
dict["insert"];             // 插入 {"insert", ""}

// 用法二:插入 + 赋值
dict["left"] = "左边";       // key 不存在,先插入再赋值

// 用法三:修改(key 存在时直接修改 value)
dict["left"] = "左边,剩余";  // key 存在,原地修改

// 危险用法:以下代码本意是"查找",但 key 不在时会偷偷插入!
cout << dict["right"] << endl;  // right 本不存在,却被插入了一个空值!

这是使用 map 时最常见的坑:如果你只想"看看"某个 key 在不在,请用 find 或 count,不要在不确定 key 是否存在时用 [],否则它会给 map 塞入一个"空数据"。

6.3 operator[] 实战:统计词频

有了 operator[],统计任务变得极其简洁。比如统计一堆水果出现的次数:

用传统方式需要 7 行:

string arr[] = {
    "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果",
    "西瓜", "苹果", "香蕉", "苹果", "香蕉"
};
map<string, int> countMap;

// 旧式写法——先 find,再判断
for (const auto& str : arr)
{
    auto ret = countMap.find(str);
    if (ret == countMap.end())
        countMap.insert({str, 1});
    else
        ret->second++;
}

用 operator[] 只需 3 行:

map<string, int> countMap;
for (const auto& str : arr)
{
    countMap[str]++;  // 一行搞定!
}

for (const auto& e : countMap)
    cout << e.first << ":" << e.second << endl;

// 苹果:6
// 西瓜:3
// 香蕉:2

这里的执行逻辑是:

  1. 第一次遇到"苹果":key 不存在,[] 插入 {"苹果", 0},然后 ++ 使其变为 1
  2. 之后再遇"苹果":key 已存在,[] 返回 value 引用,++ 直接递增

代码量减了一半,可读性还更高,这是 map 在设计上最令人称道的地方。


七、multimap——允许键重复的 map

multimap 和 map 的关系,就像 multiset 和 set 的关系一样——允许 key 出现多次。

multimap<string, string> dict;

// 同一个 key 可以对应多个不同的 value
dict.insert({"sort", "排序"});
dict.insert({"sort", "排序2"});
dict.insert({"sort", "排序1"});
dict.insert({"sort", "排序3"});
dict.insert({"sort", "排序"});
dict.insert({"string", "字符串"});

dict.erase("sort");  // 删除所有 key 为 "sort" 的元素

multimap 没有 operator[]。这很合理——如果同一个 key 对应多个 value,[] 该返回哪个呢?当你需要一对多映射时,就选它,但也得接受不能直接用 [] 的事实。


八、实战二:用 map 解 LeetCode 经典题

8.1 LeetCode 138——复制带随机指针的链表

题目:给定一个链表,每个节点除了 next 指针还有一个 random 指针指向链表中的任意节点。请深拷贝这个链表。

这是 map 的经典应用场景:建立"旧节点 → 新节点"的映射关系。

class Solution {
public:
    Node* copyRandomList(Node* head) {
        map<Node*, Node*> nodeMap;  // 旧节点 → 新节点的映射

        Node* copyhead = nullptr, *copytail = nullptr;
        Node* cur = head;

        // 第一遍遍历:复制节点,建立映射
        while (cur)
        {
            if (copytail == nullptr)
                copyhead = copytail = new Node(cur->val);
            else
            {
                copytail->next = new Node(cur->val);
                copytail = copytail->next;
            }

            nodeMap[cur] = copytail;  // 记录映射关系
            cur = cur->next;
        }

        // 第二遍遍历:根据映射关系设置 random 指针
        cur = head;
        Node* copy = copyhead;
        while (cur)
        {
            if (cur->random == nullptr)
                copy->random = nullptr;
            else
                copy->random = nodeMap[cur->random];  // 通过映射找到新节点

            cur = cur->next;
            copy = copy->next;
        }

        return copyhead;
    }
};

map 在这道题里的作用是建立新旧节点的对应关系:复制时用 nodeMap[cur] = copytail 绑定,设置 random 时通过 nodeMap[cur->random] 找到对应的新节点。这个"映射表"的思路在很多需要做对象间转换的题目中都能派上用场。

8.2 LeetCode 692——前 K 个高频单词

题目:给定一个单词列表,返回出现频率最高的前 K 个单词,频率相同时按字母顺序排列。

这道题展示了 map + STL 排序算法的组合威力:

class Solution {
public:
    struct Compare
    {
        bool operator()(const pair<string, int>& x,
                        const pair<string, int>& y) const
        {
            return x.second > y.second;  // 按频率降序
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        // 第一步:用 map 统计词频
        map<string, int> countMap;
        for (auto& e : words)
            countMap[e]++;

        // 第二步:转存到 vector 用于排序
        vector<pair<string, int>> v(countMap.begin(), countMap.end());

        // 第三步:稳定排序——频率相同的按 map 已有的字典序保留
        stable_sort(v.begin(), v.end(), Compare());

        // 第四步:取前 K 个
        vector<string> strV;
        for (int i = 0; i < k; ++i)
            strV.push_back(v[i].first);

        return strV;
    }
};

这里有两个精巧的设计细节:

第一,为什么用 stable_sort 而不是 sort?

因为 map 已经按 key(单词)的字典序排好了。当我们按频率排序时,频率相同的单词需要保持字典序。stable_sort 保证相等元素的相对顺序不变,恰好保留了 map 给出的字典序。

第二,能不能用 priority_queue 替代 vector + sort?

可以,而且更适合数据量巨大的场景:

// 用 priority_queue 取 Top K
priority_queue<pair<string, int>, vector<pair<string, int>>, Compare>
    p(countMap.begin(), countMap.end());

vector<string> strV;
for (int i = 0; i < k; ++i)
{
    strV.push_back(p.top().first);
    p.pop();
}

vector + sort 建堆是 O(N),而 priority_queue 逐个插入是 O(NlogN)。但 priority_queue 取 Top K 只需要 K 次 pop,在处理海量数据时效率优势会更明显。

两种方案都行,主要看数据规模和具体需求来定。


九、总结与选择指南

9.1 四容器速查表

容器key 唯一?自动排序?有 operator[]?底层
set是是(默认升序)无红黑树
multiset否是无红黑树
map是是(按 key)有红黑树
multimap否是(按 key)无红黑树

9.2 选容器三步法

  1. 需要 key-value 映射吗?

    • 不需要 → set 或 multiset
    • 需要 → map 或 multimap
  2. key 需要唯一吗?

    • 需要唯一 → set 或 map
    • 可重复 → multiset 或 multimap
  3. 需要 operator[] 吗?

    • 需要 → 只能是 map

9.3 关键要点回顾

  • set 的元素不可修改:迭代器指向 const 值,修改会破坏树结构
  • 用 set::find,别用 std::find:O(logN) vs O(N),差了几个数量级
  • insert 返回值是宝藏:pair<iterator, bool> 告诉你插入成功与否
  • operator[] 会插入:不确定 key 在不在时,先用 find/count
  • erase(pos) 后 pos 失效:不要再使用被删除的迭代器
  • multiset/multimap 的 count 返回实际个数:不只是 0 或 1

9.4 进阶延伸

当你掌握了这些,自然会产生新的问题:如果我不需要排序,只想要更快的平均查找速度呢?那就是 unordered_map / unordered_set 的主场了——它们基于哈希表,平均 O(1) 的查找时间。但哈希表不做排序,迭代遍历没有固定顺序,各有取舍。

再往底层走,map/set 系列的红黑树实现(AVL 树的平衡优化、旋转与变色)也是一个非常值得深入的方向。理解了底层,你对这些容器"为什么这么设计、为什么有这些限制"就会有更深刻的体会。


如果有问题或建议,欢迎评论区交流!

【制作100个unity游戏之28】花半天时间用unity复刻童年4399经典小游戏《黄金矿工》(附带项目源码) 在游戏发展史上,有些游戏以其简单而耐玩的特性,深深地烙印在了玩家的记忆中。《黄金矿工》就是其中之一,它曾经在4399等游戏平台上掀起了一股游戏热潮。这款游戏不仅给无数玩家带来了欢乐,还让他们体验到了挖掘金矿的刺激与乐趣。在这个项目中,我们将花费半天的时间,利用Unity引擎,重新打造这款经典小游戏。通过复刻《黄金矿工》,我们不仅是在向童年的回忆致敬,更是在挖掘游戏设计的精髓。在这个过程中,我们将学习如何实现游戏的核心玩法,设计简洁而有效的游戏机制。 阅读详情

相关推荐

零代码搭建专业知识库:Wiki.js+cpolar让团队协作像写笔记一样简单

"项目文档又找不到了!“团队负责人小张第N次在群里看到这样的抱怨——技术文档分散在邮件、网盘和个人电脑里,新人入职要花一周熟悉文档位置,远程协作时版本混乱更是家常便饭。Wiki.js与cpolar内网穿透服务的出现,就像给团队协作装上了"中央大脑”,用写Markdown笔记的简单方式,搭建一个专业的知识库系统。普通人对知识管理的需求其实很简单:方便记录、容易查找、大家能用。但传统方案把这个过程搞得异常复杂:建服务器、配环境、学语法、搞权限……大部分团队还没开始就放弃了。

Yawesh的博客 2034

【C++】set和map

map与set也十分的相似,map是K/V的模型,set是K的模型map也有两种区别与set和multiset相同,只是键值是否允许冗余的差别不过map的插入就比较特别了我们发现insert的参数是一个value_type类型然后我们发现它实际上是一个pair{T1 first;T2 second;{}{}};用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。

m0_62179366的博客 8180

Ubuntu22.04+Docker一键部署Autoware Universe避坑指南(附鱼香ROS配置)

本文详细介绍了在Ubuntu22.04系统中使用Docker一键部署Autoware Universe的完整流程,包括鱼香ROS工具链配置、Docker环境优化及VSCode开发环境集成。通过实战指南帮助开发者快速搭建自动驾驶开发环境,解决常见部署问题,提升开发效率。

weixin_29254673的博客 413

C++set和map详细介绍

在本篇文章中,我们将会学到关联式容器set,multiset,map,multimap。其中前两种容器对应我们上篇二叉树文章中的K模型,后两者容器对应我们的KV模型。我们来详细看一下吧!!!看一下模板参数🌟T:底层存储的数据类型🌟Compare:比较方式,默认按照小于方式比较🌟Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理set文档介绍set是按照一定次序存储元素的容器。

lim6ere的博客 2133

【SLG游戏服务器开发手册】(ROK Like)沙盘地图篇一,菱形瓦片与笛卡尔坐标系的转换(附调试工具)

轴向坐标:以菱形网格对角方向为基准轴,记作(q, r)菱形瓦片宽度 w=2a,高度 h=a(宽高比2:1)

代码时光 978

基于紫光展锐平台的音频调用到hal层逻辑

基于紫光展锐平台的音频调用到hal层逻辑 1、数据流程图 AudioPolicyService和AudioFlinger的创建: 这两个服务都在audioserver中启动,文件路径: frameworks/av/media/audioserver/main_audioserver.cpp 从AudioFlinger和AudioPolicyService的创建,到output的打开,以及AudioFlinger开始往底层写入数据的具体流程如下图: #mermaid-svg-kjHL4XWwkQXN6NdA

weixin_55053963的博客 1354

c++ - 第16节 - map和set

翻译:1.set是按照一定次序存储元素的容器2.在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。3.在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。4.set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。5.set在底层是用二叉搜索树(红黑树)实现的。

qq_45113223的博客 1350

2025华东杯A/B/C题解题思路+可运行代码参考

这些因素包括但不限于:助滑坡的坡度、运动员的质量、滑雪板的接触面与雪地的摩擦力、空气阻力系数、运动员的体型和衣物形态等。助滑坡是运动员滑行至起跳台前的最后一段坡道,这一段坡道的坡度、长度和运动员的姿势会直接影响到起跳时的初始速度。运动员的滑行速度不仅受助滑坡的坡度影响,还受到摩擦力、空气阻力和重力等多方面因素的影响。通过合理的姿势调整,运动员能够有效减少空气阻力,增加身体的重力加速度,进而提升滑行速度。助滑坡的角度通常介于10°到12°之间,而运动员的滑行速度将受到重力、摩擦力和空气阻力的共同作用。

qq_52590045的博客 1796

C++ - set 和 map详解

详细介绍了 set 以及 map.

大海洋的博客 2960

ATR2660:卫星导航高增益低噪声放大器芯片数据手册

中国BDS(北斗卫星导航系统),美国的GPS,俄罗斯的GLONASS和欧盟的GALILEO导航系统应用而专门设计。芯片支持3.3V至5V宽电源供电。采用2级放大器的结构设计,具有28dB高增益和0.85dB的低噪声系数。支持BDS、GPS、GALILEO、GLONASS等L。典型功率增益:30dB@5V;典型输入P1dB:-18dBm@3.3V;典型工作电流:12.7mA@3.3V;宽供电电压范围:3.3V~5V;典型噪声系数:0.85dB;频段的多个卫星导航系统;ATR2660是一颗。

YHPsophie的博客 559

Oracle MCP Server实战:自然语言如何重塑数据库交互体验

本文深入探讨了Oracle MCP Server如何通过自然语言交互技术革新数据库操作体验。作为Oracle数据库的革命性工具,MCP Server集成了先进的Text-to-SQL技术,允许用户使用自然语言直接查询数据库,大幅降低使用门槛。文章详细介绍了从环境搭建、实战案例到企业级部署的全流程,特别强调了中文自然语言处理能力和安全最佳实践,为DBA和开发者提供了从传统SQL到智能交互的转型指南。

u9v0w的博客 282

【C++】map 和 set

map/multimap 的使用以及 set/multiset 的使用

在平淡的日子里寻找存在的价值 1629

《Python星球日记》 第73天:情感分析与主题建模

《Python星球日记》 第73天:情感分析与主题建模,今天我们将探索两个自然语言处理领域的重要技术:情感分析和主题建模。这两项技术在社交媒体分析、用户反馈处理、市场研究等多个领域有着广泛应用。

Code_流苏:在代码中寻诗意,在实践中觅真知 918

C++中map和set的详解

在C++编程中,map和set是标准模板库(STL)中两种非常重要的关联容器。它们基于平衡二叉搜索树(通常是红黑树)的数据结构来实现,提供了高效的数据存储和检索功能。本文将详细介绍map和set的特点、用法以及一些常见的操作示例。1. map的基本概念map是一个键值对容器,其中每个键都是唯一的,且按照升序排序。map数据是有序的,方便进行高效的查找、插入和删除操作。查找、插入、删除的平均和最坏时间复杂度都是O(log n),其中n是map中元素的个数。2. map的定义与初始化要使用map。

yang789022的博客 880

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【C++】详解map和set基本接口及使用

详解C++ map和set的接口用法,不会就快来和我一起学!

小羊study_sheep的博客 2630

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【C++】map和set详解

set容器:它是一个关联容器,用于存储唯一的元素,且按照一定的顺序排列。set容器中的元素按照默认的排序顺序存储,或者可以通过自定义的排序函数进行排序。set容器实际上是一个红黑树(red-black tree)实现的。set容器中的元素会自动按照键的顺序进行排序,保持元素的有序性。同时,set容器中的元素是唯一的,即相同的元素只能出现一次。map容器:它是一个关联容器,用于存储键值对(key-value pairs)。其中的每个元素都由一个键(key)和一个值(value)组成。

qq_64818885的博客 1415

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【C++】: STL详解 —— set和map类

C++标准库提供了多种容器,用于高效管理和操作数据集合。这些容器可分为以下几类: 顺序容器(Sequence Containers)关联容器(Associative Containers) 容器适配器(Container Adapters)其他类容器类型 set 是一个有序关联容器,存储唯一键(Key),键本身即为其值(没有额外的Value)。 元素按键的严格弱序规则(默认升序)自动排序,不允许重复键。map 是一个有序关联容器,存储键值对(Key-Value Pair),其中键(Key)唯一

元清的博客 1427

详解C++之map和set

本文介绍了C++ STL中的关联式容器,重点讲解了set和multiset的使用。关联式容器存储的是<key,value>结构的键值对,相比序列式容器具有更高的检索效率。set基于红黑树实现,具有自动排序和去重功能,元素不可修改;multiset允许键值冗余。文章详细介绍了set的构造方法、迭代器使用、插入删除操作,以及set与multiset的区别,如multiset允许重复元素和count()函数返回重复元素数量等特性。通过代码示例展示了set和multiset的基本操作和实际应用场景。

weixin_63997543的博客 913

c++ map和set功能详解

1. set是按照一定次序存储元素的容器。2. 在 set 中,元素的 value 也标识它 (value 就是 key ,类型为 T) ,并且每个 value 必须是唯一的。set中的元素不能在容器中修改( 元素总是 const) ,但是可以从容器中插入或删除它们。3.在内部, set 中的元素总是按照其内部比较对象 ( 类型比较 ) 所指示的特定严格弱排序准则进行 排序。

w8848w的博客 945

C++中的map 和 set 详解

C++ STL中的关联式容器(set/map)基于红黑树实现,提供高效的增删查操作(O(logN))。set用于存储唯一key,支持自动去重和有序遍历;map存储key-value对,通过[]运算符实现快速访问和修改。set/map的迭代器均为const,避免破坏结构。multiset/multimap允许key重复,但find/count/erase行为有所不同。典型应用场景包括数组去重、频率统计、查找重复节点等问题。这些容器在需要快速查找、自动排序和键值映射的场景中具有显著优势,是处理关联数据的强大工具

2403_87794049的博客 930
上一篇: 二叉搜索树详解
下一篇: AVL树原理与实现详解——旋转如何掰正一棵树
jinyishu_
博客等级 码龄1年 53粉丝 82原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值