【C++笔记】map和set的使用

【C++笔记】map和set的深度剖析

🔥个人主页大白的编程日记

🔥专栏C++笔记


文章目录

  • 【C++笔记】map和set的深度剖析
    • 前言
    • 一.set
      • 1.1 序列式容器和关联式容器
      • 1.2 set系列的使用
      • 1.3 set类的介绍
      • 1.4 set的构造和迭代器
      • 1.5 set的增删查
      • 1.6 lower_bound和lower_bound
      • 1.7 multiset和set的差异
      • 1.8 set的应用
    • 二. map系列的使用
      • 2..1 map和multimap参考文档
      • 2.2 map类的介绍
      • 2.3 pair的介绍
      • 2.4 pair使用
      • 2.5 map的构造
      • 2.6 map增删查
      • 2.7 operator[]
      • 2.8 multimap和map的差异
      • 2.9 map的应用
    • 后言

前言

哈喽,各位小伙伴大家好!上期我们讲了位图和布隆过滤器。今天我们来讲一下map和set的使用。话不多说,我们进入正题!向大厂冲锋
在这里插入图片描述

一.set

1.1 序列式容器和关联式容器

  • 序列式容器
    前面我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间⼀般没有紧密的关联关系,比如交换⼀下,他依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。

  • 关联式容器
    关联式容器也是用来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是非线性结构,两个位置有紧密的关联关系,交换⼀下,他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。本章节讲解的map和set底层是红黑树,红黑树是⼀颗平衡二叉搜索树。set是key搜索场景的结构,map是key/value搜索场景的结构。

1.2 set系列的使用

set和multiset参考文档:
set和multiset参考⽂档
这里可以使用文档学习map和set.

1.3 set类的介绍

  • 声明
    set的声明如下,T就是set底层关键字的类型
template < class T,                        // set::key_type/value_typeclass Compare = less<T>,        // set::key_compare/value_compareclass Alloc = allocator<T>      // set::allocator_type> class set;

  • 仿函数
    set默认要求T支持小于比较,如果不支持或者想按自己的需求走可以自行实现仿函数传给第二个模版参数

  • 空间配置器
    set底层存储数据的内存是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个参数。

  • 模版参数
    ⼀般情况下,我们都不需要传后两个模版参数。

  • 底层结构
    set底层是用红黑树实现,增删查效率是 ,迭代器遍历是走的搜索树的中序,所以是有序的。

1.4 set的构造和迭代器

set的构造我们关注以下几个接口即可。

set的支持正向和反向迭代遍历,遍历默认按升序顺序,因为底层是二叉搜索树,迭代器遍历走的中序;支持迭代器就意味着支持范围for,set的iterator和const_iterator都不⽀持迭代器修改数据,修改关键字数据,破坏了底层搜索树的结构。

// 迭代器是⼀个双向迭代器
iterator -> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

1.5 set的增删查

  • insert
    set的插入主要支持key关键字插入,迭代器位置插入,迭代器区间插入,initializer_list插入

    这里有两个2会插入失败。因为set不允许介质冗余。同时插入后的数据中序遍历就是有序的。所以set有排序和去重的功能。
    默认是升序。如果想控制升降序就用仿函数控制即可。
    如果是降序那就是大的数在左边,小的数在右边。
    中序遍历出来就是降序。

    initializer_list插入。

  • 修改
    set不允许修改。因为set底层是红黑树,也就是二叉平衡搜索树的变形。所以修改key会破坏树的性质。

  • find
    set的查找支持key关键字查找。同时底层也是利用二叉搜索树性质查找。
    查找高度次。所以是O(logN).
    如果找到返回该位置的迭代器。
    如果没找到就返回end迭代器

    这里的value是为了和map对称实际还是key。

    也可以用count查找。返回key的个数。

  • erase
    有三种方式:
    迭代器删除,key关键字删除,迭代器区间删除。

    因为默认是升序,同时迭代器走的是中序遍历。
    所以直接删除begin就是最小值。


    如果删除失败就返回end迭代器。
    按照key关键字删除

    返回删除个数也是为了和map对称。

注意因为删除后迭代器失效,所以erase返回迭代器的下一个位置。

  • 迭代器失效
    set删除后迭代器失效。
    在这里插入图片描述

    所以我们删除迭代器后就不要访问了。
    迭代器删除

1.6 lower_bound和lower_bound

  • lower_bound
    返回大于等于val位置的迭代器在这里插入图片描述

  • upper_bound
    返回大于val位置的迭代器。
    这两个接口的作用在迭代器区间删除的时候,删除时迭代器区间默认都是左边右开
    这是我们就可以用lower_bound查找左端点,x存在就是x迭代器。不在就会找到大于x的第一个迭代器位置。upper_bound查找右端点的下一个位置。就可以删除形成某段特定值的左闭右开的区间了。
    底层查找也是利用二叉搜索树的性质查找。效率也很高。

1.7 multiset和set的差异

multiset和set的使用基本完全类似,主要区别点在于multiset支持值冗余,那么
insert/find/count/erase都围绕着支持值冗余有所差异,具体参看下面的样例代码理解。

#include<iostream>
#include<set>
using namespace std;
int main()
{// 相⽐set不同的是,multiset是排序,但是不去重multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };auto it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;// 相⽐set不同的是,x可能会存在多个,find查找中序的第⼀个int x;cin >> x;auto pos = s.find(x);while (pos != s.end() && *pos == x){cout << *pos << " ";++pos;}cout << endl;// 相⽐set不同的是,count会返回x的实际个数cout << s.count(x) << endl;// 相⽐set不同的是,erase给值时会删除所有的xs.erase(x);for (auto e : s){cout << e << " ";}cout << endl;return 0;
}


multiset也排序但是不去重。
这里multiset的查找和删除和set重点区别一下。

  • 查找
    找到中序的第一个。

  • 删除
    如果按照key关键字删除就把所有相同值的节点都删除。



multiset和set的接口基本都一致。

1.8 set的应用

这里我们来做两个题体会一下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){it2++;}else if(*it1<*it2){it1++;}else{ret.push_back(*it1);it1++;it2++;}}return ret;}
};

  • 题目二
    环形链表2

  • 思路分析

  • 代码实现

class Solution {
public:ListNode *detectCycle(ListNode *head) {set<ListNode*> tmp;ListNode *cur=head;while(cur!=nullptr&&!tmp.count(cur)){tmp.insert(cur);cur=cur->next;}return cur;}
};

二. map系列的使用

2…1 map和multimap参考文档

这是map和multimap参考文档:
map和multimap参考⽂档

2.2 map类的介绍

map的声明如下,Key就是map底层关键字的类型,T是map底层value的类型,set默认要求Key支持小于比较,如果不支持或者需要的话可以自行实现仿函数传给第⼆个模版参数,map底层存储数据的内存是从空间配置器申请的。⼀般情况下,我们都不需要传后两个模版参数。map底层是⽤红黑树实现,增删查改效率是O(logN) ,迭代器遍历是走的中序,所以是按key有序顺序遍历的。

template < class Key,                                     // map::key_typeclass T,                                       // map::mapped_typeclass Compare = less<Key>,                     // map::key_compareclass Alloc = allocator<pair<const Key,T> >    // map::allocator_type> class map;

2.3 pair的介绍

map底层的红黑树节点中的数据,使用pair<Key, T>存储键值对数据。

typedef pair<const Key, T> value_type;
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){}
};

`


pair是一个类模板。主要包含first和second两个成员。
可以理解为pair就是个结构体。、
所以我们现在就可以理解为之前我们是分散存放key和value。
现在放在一个结构体里面。

  • make_pair
    make_pair也是一个类模板。作用就是传两个参数,编译器推导出类型后,生成一个pair对象返回。在这里插入图片描述

2.4 pair使用

这里用pair写起来就比较方便。

#include<iostream>
#include<map>
using namespace std;
int main()
{// insert插⼊pair对象的4种⽅式,对⽐之下,最后⼀种最⽅便map<string, string> dict;pair<string, string> kv1("first", "第一个");dict.insert(kv1);dict.insert(pair<string, string>("second", "第二个"));dict.insert(make_pair("sort", "排序"));dict.insert({ "auto", "自动的" });// "left"已经存在,插⼊失败dict.insert({ "left", "左边,剩余" });while (it != dict.end()){//cout << (*it).first <<":"<<(*it).second << endl;// map的迭代基本都使⽤operator->,这⾥省略了⼀个->// 第⼀个->是迭代器运算符重载,返回pair*,第⼆个箭头是结构指针解引⽤取pair数据//cout << it.operator->()->first << ":" << it.operator->()-> second << endl;cout << it->first << ":" << it->second << endl;++it;}cout << endl;return 0;
}

同时这里遍历的时候,我们不能这样写。因为pair不支持流插入和流提取。

所以我们可以这样显示的写出first和second

本质是通过运算符重载找到pair*,在通过pair*访问first和second
在这里插入图片描述
但是为了好看就省略了一个->.

注意这里我们插入了第二个auto时,value也不会修改。
插入相同的值就失败了。因为map不允许冗余。multimap才可以插入多个值。

2.5 map的构造

map的构造我们关注以下几个接口即可。
map的支持正向和反向迭代遍历,遍历默认按key的升序顺序,因为底层是⼆叉搜索树,迭代器遍历走的中序;支持迭代器就意味着支持范围for,map支持修改value数据,不支持修改key数据,修改关键字数据,破坏了底层搜索树的结构。

// empty (1) ⽆参默认构造
explicit map(const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template <class InputIterator>
map(InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type & = allocator_type());
// copy (3) 拷⻉构造
map(const map& x);
// initializer list (5) initializer 列表构造
map(initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
// 迭代器是⼀个双向迭代器
iterator->a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();


构造时我们通常这样初始化,因为很方便。

2.6 map增删查

map的增删查关注以下几个接口即可:
map增接口,插入的pair键值对数据,跟set所有不同,但是查和删的接口只用关键字key跟set是完全类似的,不过find返回iterator,不仅仅可以确认key在不在,还找到key映射的value,同时通过迭代还可以修改value

Member types
key_type->The first template parameter(Key)
mapped_type->The second template parameter(T)
value_type->pair<const key_type, mapped_type>
// 单个数据插⼊,如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败
pair<iterator, bool> insert(const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊
void insert(initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert(InputIterator first, InputIterator last);
// 查找k,返回k所在的迭代器,没有找到返回end()
iterator find(const key_type& k);
// 查找k,返回k的个数
size_type count(const key_type& k) const;
// 删除⼀个迭代器位置的值
iterator erase(const_iterator position);
// 删除k,k存在返回0,存在返回1
size_type erase(const key_type& k);
// 删除⼀段迭代器区间的值
iterator erase(const_iterator first, const_iterator last);
// 返回⼤于等k位置的迭代器
iterator lower_bound(const key_type& k);
// 返回⼤于k位置的迭代器
const_iterator lower_bound(const key_type& k) const;
  • insert
    insert插入一个pair的键值对

  • erase
    map的erase只跟key有关。
    在这里插入图片描述

  • find
    map的查找也只跟key有关系,和value无关。

2.7 operator[]

这里我们快速统计水果出现的次数。

#include<iostream>
#include<map>
#include<string>
using namespace std;
int main(){// 利⽤find和iterator修改功能,统计⽔果出现的次数string arr[] = { "苹果", "西⽠", "苹果", "西⽠", "苹果", "苹果", "西⽠","苹果", "⾹蕉", "苹果", "⾹蕉" };map<string, int> countMap;for (const auto& str : arr){// 先查找⽔果在不在map中// 1、不在,说明⽔果第⼀次出现,则插⼊{⽔果, 1}// 2、在,则查找到的节点中⽔果对应的次数++auto ret = countMap.find(str);if (ret == countMap.end()){countMap.insert({ str, 1 });}else{ret->second++;}}for (const auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;return 0;
}


这里我们也可以用operator[]一行搞定。


为什么呢?这就得好好研究operator[]的底层了。

这里的operator[]有三种功能:插入 查找 修改。

2.8 multimap和map的差异

multimap和map的使用基本完全类似,主要区别点在于multimap支持关键值key冗余,那么insert/find/count/erase都围绕着支持关键值key冗余有所差异,这里跟set和multiset完全⼀样,比如find时,有多个key,返回中序第⼀个。其次就是multimap不支持[],因为支持key冗余,[]就只能支持插入了,不能支持修改。

  • find
    有相同查找中序的第一个。

  • insert
    插入肯定成功,因为允许介质冗余。

  • erase
    有相同值全部删除。

  • equal_range
    这里equal_range作用主要是传一个key。
    那会就会返回一段迭代器区间。
    这段区间是所有key节点的左闭右开区间。
    左端点指向第一个key的迭代器,右端点指向第二个key的迭代器下一个位置。
    在这里插入图片描述

  • operator[]
    multimap不支持[].因为多个key,那该返回哪一个呢?
    所以不支持。

2.9 map的应用

  • 题目一
    随机链表的复制

  • 思路分析

  • 代码实现

class Solution {
public:Node* copyRandomList(Node* head) {map<Node*,Node*> hash;Node* phead=nullptr,*tail=nullptr;Node* pur=head;while(pur){Node* node=new Node(pur->val);if(phead){tail->next=node;tail=node;}else{tail=phead=node;}hash.insert({pur,node});//建立映射关系pur=pur->next;}pur=head;while(pur){hash[pur]->random=hash[pur->random];pur=pur->next;}return phead;}
};

  • 题目二
    前k个高频单词

  • 思路分析
    在这里插入图片描述

  • 代码实现

stable_sort:

class Solution {
public:using  PSI=pair<string,int>;struct cmp{bool operator()(const PSI& a,const PSI& b)//比较{return a.second>b.second;}};vector<string> topKFrequent(vector<string>& words, int k) {map<string ,int> countmap;vector<string> ret;for(auto& x:words)//统计单词频次{countmap[x]++; }vector<PSI> v(countmap.begin(),countmap.end());stable_sort(v.begin(),v.end(),cmp());for(int i=0;i<k;i++)//提取结果{ret.push_back(v[i].first);}return ret;}
};

仿函数控制稳定:

class Solution {
public:using  PSI=pair<string,int>;struct cmp{bool operator()(const PSI& a,const PSI& b)//比较{return a.second>b.second||(a.second==b.second&&a.first<b.first);}};vector<string> topKFrequent(vector<string>& words, int k) {map<string ,int> countmap;vector<string> ret;for(auto& x:words)//统计单词频次{countmap[x]++; }vector<PSI> v(countmap.begin(),countmap.end());sort(v.begin(),v.end(),cmp());for(int i=0;i<k;i++)//提取结果{ret.push_back(v[i].first);}return ret;}
};

堆top-k:

class Solution {
public:using  PSI=pair<string,int>;struct cmp{bool operator()(const PSI& a,const PSI& b)//比较{return a.second<b.second||(a.second==b.second&&a.first>b.first);}};vector<string> topKFrequent(vector<string>& words, int k) {vector<string> ret(k);unordered_map<string ,int> hash;for(auto& x:words)//统计单词频次{hash[x]++;}priority_queue<PSI,vector<PSI>,cmp> heap(hash.begin(),hash.end());for(int i=0;i<k;i++)//提取结果{ret[i]=heap.top().first;heap.pop();}return ret;}
};

在这里插入图片描述

后言

这就是C++三大特性之继承。大家自己好好消化!今天就分享到这!感谢各位的耐心垂阅!咱们下期见!拜拜~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/61740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot+mybatis对接使用postgresql中PostGIS地图坐标扩展类型字段

方案一&#xff08;完全集成和自动解析&#xff09;&#xff1a; <dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId></dependency> 使用 org.postgresql.geometric包下的 PGpoint 类来接收数据库中POINT…

《只狼》运行时提示“mfc140u.dll文件缺失”是什么原因?“找不到mfc140u.dll文件”要怎么解决?教你几招轻松搞定

《只狼》运行时提示“mfc140u.dll文件缺失”的科普与解决方案 作为一名软件开发从业者&#xff0c;在游戏开发和维护过程中&#xff0c;我们经常会遇到各种运行时错误和系统报错。今天&#xff0c;我们就来探讨一下《只狼》这款游戏在运行时提示“mfc140u.dll文件缺失”的原因…

华为HarmonyOS 让应用快速拥有账号能力 -- 3 获取用户手机号

场景介绍 当应用对获取的手机号时效性要求不高时&#xff0c;可使用Account Kit提供的手机号授权与快速验证能力&#xff0c;向用户发起手机号授权申请&#xff0c;经用户同意授权后&#xff0c;获取到手机号并为用户提供相应服务。以下只针对Account kit提供的手机号授权与快…

linux环境人大金仓数据库修改密码

1.进入人大金仓安装目录 cd /home/opt/Kingbase/ES/V9/Server/bin2.连接数据库 ./ksql -U system -d mydb -h 127.0.0.1 -p 54321-u 用户名 -d 数据库名 -h ip地址 -p 端口号 3.修改密码 ALTER USER system WITH PASSWORD 密码;

使用R语言进行美国失业率时空分析(包括绘图)

今天写一篇利用R语言&#xff0c;针对面板数据的简单分析与绘图。让我们直接开始把。 一、数据准备 这次的示例数据非常简单&#xff0c;只有一个shp格式的美国区县矢量数据&#xff0c;我们在QGIS中打开数据查看一下它的属性表。事实上我们需要的数据都在属性表的字段中。 二…

单片机几大时钟源

在单片机中&#xff0c;MSI、HSI和HSE通常指的是用于内部晶振配置的不同功能模块&#xff1a; MSI (Master Oscillator System Interface)&#xff1a;这是最低级的一种时钟源管理单元&#xff0c;它控制着最基本的系统时钟&#xff08;SYSCLK&#xff09;&#xff0c;一般由外…

前端开发 之 15个页面加载特效上【附完整源码】

文章目录 一&#xff1a;彩球环绕加载特效1.效果展示2.HTML完整代码 二&#xff1a;跷跷板加载特效1.效果展示2.HTML完整代码 三&#xff1a;两个圆形加载特效1.效果展示2.HTML完整代码 四&#xff1a;半环加载特效1.效果展示2.HTML完整代码 五&#xff1a;音乐波动加载特效1.效…

Spring入园须知

序 聊 Spring&#xff0c;先从发展历史谈起&#xff0c;对整个生态有个大致认识&#xff0c;最后再看下 Spring 依赖的基础机制——IoC 和 AOP&#xff0c;就达到入门须知的目的了。毕竟 Spring 太大了&#xff0c;如果把话题扯得太宽泛太细节&#xff0c;很可能会迷失在 Spri…

作品截图_

openstack project create --domain default --description "姓氏" xingopenstack user create --domain default --password-prompt --description "名字" mingziopenstack role create --description "姓名首字母" xmzopenstack role add --pr…

使用API管理Dynadot域名,设置默认域名服务器ip信息

前言 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…

聚合支付系统官方个人免签系统三方支付系统稳定安全高并发

系统采用fastadmin框架独立全新开发&#xff0c;安全稳定,系统支持代理、商户、码商等业务逻辑。 针对最近一-些JD&#xff0c;TB等业务定制&#xff0c;子账号业务逻辑API 非常详细&#xff0c;方便内置对接! 注意&#xff1a;系统没有配置文档很使用教程&#xff0c;不清楚…

vue结合canvas动态生成水印效果

在 Vue 项目中添加水印可以通过以下几种方式实现&#xff1a; 方法一&#xff1a;使用 CSS 直接通过 CSS 的 background 属性实现水印&#xff1a; 实现步骤 在需要添加水印的容器中设置背景。使用 rgba 设置透明度&#xff0c;并通过 background-repeat 和 background-size…

S32K324 信息安全开发-Secure Debug原理及其实现

文章目录 前言Secure debug原理LC(Life Cycle)Application debug key/password (ADKP)固定密钥的实现方案一机一密实现方案AUTH_MODE的区别代码实现ADKP写入确认认证方式写入LC总结前言 车载信息安全对于MCU的要求越来越高,debug口作为直接刷写调试程序的通道,对其进行保护是…

iptables之地址转换

1、自定义链 iptables -N hello #在filter表中创建一个自定义链&#xff0c;链名hello,自定义链名可以任意大小写 iptables -E hello happy #修改自定义的链名 iptables -t filter -I happy -s 192.168.206.30 -p icmp -j REJECT #禁止192.168.206.30ping本机 自定义没有策略&a…

[241129] Docker Desktop 4.36 发布:企业级管理功能、WSL 2 增强 | Smile v4.0.0 发布

目录 Docker Desktop 4.36 发布&#xff1a;企业级管理功能、WSL 2 和 ECI 增强Smile v4.0.0 发布&#xff01;Java 机器学习库迎来重大升级 Docker Desktop 4.36 发布&#xff1a;企业级管理功能、WSL 2 和 ECI 增强 Docker Desktop 4.36 带来了强大的更新&#xff0c;简化了…

Linux信号集、信号的阻塞信号驱动

一、信号集 信号的三种方式&#xff0c;即使是忽略&#xff0c;也仍然打断了进程的进行&#xff08;相当于是捕捉了信号&#xff0c;执行的了空函数什么都没做&#xff09;&#xff0c;可如果在访问重要资源时不希望被打断呢&#xff1f; 可以用阻塞&#xff0c;即产生了信号却…

什么是内网什么是外网?区别是什么

内网和外网是计算机网络中的两个基本概念&#xff0c;它们在定义、特点和使用场景上有显著的区别。‌虎观代理小二将带大家详细了解内网与外网的定义以及它们之间的主要差异&#xff0c;帮助读者更好地理解和应用这两种网络。 内网&#xff08;局域网&#xff0c;LAN&#xff0…

如何在 Spring Cloud 集成 Micrometer Tracing?

1.什么是 Micrometer Tracing&#xff1f; Micrometer Tracing 是一个用于微服务架构的追踪库&#xff0c;它提供了一种简单而强大的方式来收集和报告分布式系统中的性能和调用链信息。它是 Micrometer 库的一部分&#xff0c;Micrometer 是一个用于应用程序监控的指标收集工具…

爬虫专栏第五篇:Python BeautifulSoup 库全解析:从解析器到网页数据爬取实战

简介&#xff1a;本文围绕 Python 的 BeautifulSoup 库展开&#xff0c;介绍了其安装方式&#xff0c;详细解析了各类解析器&#xff08;如标准库、lxml 库、xml 库、html5lib 等&#xff09;的特点与作用&#xff0c;并通过代码案例展示不同解析器在实际应用中的表现。同时&am…

架构06-分布式共识

零、文章目录 架构06-分布式共识 1、分布式共识 &#xff08;1&#xff09;基本概念 **分布式共识&#xff1a;**在分布式系统中&#xff0c;多个节点之间达成一致的过程。**复杂性来源&#xff1a;**网络的不可靠性和请求的并发性。**应用场景&#xff1a;**如何确保重要数…