【C++进阶】2024年了set、map还搞不懂底层细节?

头像
🚀个人主页:@小羊
🚀所属专栏:C++
很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述

目录

  • 一、前情提要
    • 1、什么是关联式容器?
    • 2、键值对又是什么?
  • 二、树形结构的关联式容器
    • 1、set
      • 1.1 set 介绍
      • 1.2 set 模版参数列表
      • 1.3 set 的相关操作
    • 2、multiset
      • 2.1 multiset 介绍
      • 2.2 count 接口
      • 2.3 find 接口
      • 2.4 erase 接口
    • 3、map
      • 3.1 map介绍
      • 3.2 map的元素存储
      • 3.3 map的几种初始化方式
      • 3.4 使用map计数
      • 3.5 [ ]运算符重载
    • 4、multimap
      • 4.1 multimap 介绍


一、前情提要

在学习setmap之前,我们首先来了解一下 关联式容器键值对 这两个概念。

1、什么是关联式容器?

前面我们学习过的vectorListdequeforward_list等都是序列式容器,底层为线性序列的数据结构,里面存储的是元素本身。
关联式容器也是用来存储数据的,与序列式容器不同的是,关联式容器里面存的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。

基于红黑树的关联容器:

  • set:存储唯一键的集合
  • multiset:存储可以有重复键的集合
  • map:存储唯一键及其关联值的映射
  • multimap:存储可以有重复键及其关联值的映射
  • 特点:内部以红黑树实现,元素默认按键的升序排列,支持快速查找、插入和删除操作

2、键值对又是什么?

键值对是一种将两个相关的值组合在一起的数据结构,具有一一对应的关系,该结构一般只包含两个成员变量key和Value,key代表键值,Value代表与key对应的信息。

特点:

  • 唯一性:在大多数情况下,键(Key)是唯一的,这意味着一个键只能映射到一个值(Value)。然而,在某些特殊情况下(如multimap或unordered_multimap),一个键可以映射到多个值
  • 无序性:键值对的存储顺序通常不是由键或值的顺序决定的,除非使用了某种特定的排序算法或数据结构(如基于红黑树的map或set)。然而,有些容器(如unordered_map或unordered_set)确实提供了基于哈希表的快速查找,但它们的元素是无序的
  • 灵活性:键值对可以存储几乎任何类型的数据,只要键和值的数据类型在容器声明时指定或兼容

SGI-STL中键值对的定义:

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)
{}
};

通过上面简单的介绍了解一下关联式容器和键值对,我们再学习set和map会相对清晰一些。


二、树形结构的关联式容器

根据应用场景的不同,STL总共实现了两种不同结构的管理式容器:树形结构和哈希结构。本篇文章我们学习树形结构。

树形结构关联式容器主要包括map、set、multimap和multiset。这些容器通过键值对(key-value)的形式存储数据,并且基于树型结构(平衡搜索树,即红黑树)来实现,确保了容器中的元素是有序的。

1、set

1.1 set 介绍

  • set 文档介绍。
  • 使用set需要包头文件<set>

| set的底层使用二叉搜索树(红黑树)实现的,所以set具有以下的性质:

  • 元素唯一: set中的每个元素都是唯一的,不允许有重复的元素。如果尝试插入一个已存在的元素,该插入操作将被忽略,即set的大小不会增加
  • 快速查找: 由于 set 内部使用平衡二叉树(如红黑树)实现,因此它查找的速度很快,时间复杂度为O(LogN)
  • 元素不可修改: set中的元素不能在容器中修改(元素总是const)(因为这可能会破坏容器的排序顺序),但是可以从容器中插入或删除
  • 有序: 使用set的迭代器中序遍历set中的元素,可以得到有序序列(结合元素唯一和有序,set可以做到去重+排序

| 另外还有一些细节值得注意:

  • set中插入元素时,只需要插入value即可,不需要构造键值对
  • 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对

1.2 set 模版参数列表

在这里插入图片描述

  • T: set中存放元素的类型,实际在底层存的是<value, value>的键值对
  • Compare: set中元素默认按小于比较,如果想要按大于比较可以传相应的仿函数
  • Alloc: set中元素空间的管理方式,使用STL提供的空间配置器管理

1.3 set 的相关操作

set的构造、迭代器、容量等函数比较简单,使用起来不是很复杂,童鞋们参考上面提供的文档介绍自己看一下哈,这里就不浪费篇幅了哈,我们介绍一下set的插入、删除、查找等操作。

头像
函数声明功能
pair<iterator,bool> insert (const value_type& val)在set中插入val,实际插入的是<val, val>构成的键值对,如果插入成功,返回<该元素在set中的位置,true>,如果插入失败(val在set中已经存在),返回<val在set中的位置,false>
void erase (iterator position)删除set中position位置的元素
size_type erase ( const key_type& x )删除键值为x的元素
void erase (iterator first, iterator last)删除set中[first, last)区间的元素
iterator find ( const key_type& x ) const返回set中值为x元素的位置,返回值不可被修改
void test1()
{构造空的set//set<int> s;//s.insert(1);//s.insert(3);//s.insert(1);//s.insert(6);//s.insert(2);//s.insert(3);//s.insert(5);//s.insert(8);int arr[] = { 3,4,9,6,5,7,1,5,6,4,6,4,2,4,6,8,5,4,1,5,6,6,3,2 };//迭代器区间构造set<int> s(arr, arr + sizeof(arr) / sizeof(int));//迭代器遍历//去重+排序auto it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;//删除最小的元素s.erase(s.begin());//范围for遍历for (auto e : s){cout << e << " ";}cout << endl;
}

2、multiset

2.1 multiset 介绍

  • multiset 文档介绍
  • 使用multiset也需要包含头文件<set>

multisetset的操作、使用大致相同,所以这里也就不再赘述了(又能偷懒了),只是在某些方面有一些区别:

  • multiset也是按照特定顺序存储元素的容器,不过其元素是可以重复的
  • multiset的插入接口只需要插入即可,因为理论上multiset的插入操作一定会成功
  • multiset不会对数据去重,所以可以真正意义上的排序

另外multisetset也存在接口上的一些区别。


2.2 count 接口

  • count的作用是: 给一个值,返回这个值在当前容器中的个数。

set中也有count接口,不过set中的count接口用处不是很明显,可以用来判断某一个值在当前set中存不存在:

v

相比而言multiset中的count才能发挥它真正的作用:

在这里插入图片描述


2.3 find 接口

set中的find接口类似,multiset中的find接口作用也是在容器中搜索等效于val 的元素,如果找到,则返回指向val的迭代器,否则返回multiset::end

不过multiset中可能存在多个给定的val,而这时的find返回的是中序遍历的第一个val的迭代器,这么做的目的是能把所有的val都找出来。

找出multiset中所有的val:

int main()
{int arr[] = { 3,4,9,6,5,7,1,5,6,4,6,4,2,4,6,8,5,4,1,5,6,6,3,2 };multiset<int> mts(arr, arr + sizeof(arr) / sizeof(int));int x = 0;cin >> x;int y = mts.count(x);while (y--){cout << *(mts.find(x)) << " ";}return 0;
}

在这里插入图片描述


2.4 erase 接口

支持通过迭代器、元素值、迭代器区间来删除元素。

函数声明参数
void erase (iterator position)迭代器
size_type erase (const value_type& val)val
void erase (iterator first, iterator last)迭代器区间

multiset的erase接口和set的erase虽然看起来好像一样,但实际上有不小的差别。

来看下面三种删除操作:

void test2()
{//传迭代器删除cout << "传迭代器删除" << endl;int arr1[] = { 3,4,9,6,5,7,1,5,6,4,6,4,2,4,6,8,5,4,1,5,6,6,3,2 };multiset<int> mts1(arr1, arr1 + sizeof(arr1) / sizeof(int));for (auto e : mts1){cout << e << " ";}cout << endl;mts1.erase(mts1.find(6));multiset<int>::iterator it = mts1.begin();while (it != mts1.end()){cout << *it << " ";++it;}cout << endl;//传值删除cout << "传值删除" << endl;int arr2[] = { 3,4,9,6,5,7,1,5,6,4,6,4,2,4,6,8,5,4,1,5,6,6,3,2 };multiset<int> mts2(arr2, arr2 + sizeof(arr2) / sizeof(int));for (auto e : mts2){cout << e << " ";}cout << endl;mts2.erase(6);for (auto e : mts2){cout << e << " ";}cout << endl;//传迭代器区间删除cout << "传迭代器区间删除" << endl;int arr3[] = { 3,4,9,6,5,7,1,5,6,4,6,4,2,4,6,8,5,4,1,5,6,6,3,2 };multiset<int> mts3(arr3, arr3 + sizeof(arr3) / sizeof(int));for (auto e : mts3){cout << e << " ";}cout << endl;mts3.erase(mts3.equal_range(6).first, mts3.equal_range(6).second);for (auto e : mts3){cout << e << " ";}cout << endl;
}

在这里插入图片描述

通过结果我们不难得出:如果multiset中存在多个val,则传迭代器只会删除一个,传值和传迭代器区间会将multiset中所有的val删除。

这点是我们在平时使用时容易忽略的。


3、map

3.1 map介绍

  • map 文档介绍
  • 使用map需要包头文件<map>

| map的底层也是二叉平衡树(红黑树)实现的,所以其也具有以下性质:

  • 有序: map是关联容器,它按照特定的次序存储由键值key和值value组合而成的元素,map中的元素只按照键值key进行比较排序
  • 唯一: 每个键在map中都是唯一的(值可以不唯一),不允许有重复键。如果尝试插入一个已存在的键,则不会插入该元素,并返回此现有元素的迭代器
  • 时间复杂度: map的查找、插入和删除操作的时间复杂度通常是O(logN)

其实map和set还是非常相似的,甚至函数接口等,这里就不再过多列举了,可以对比set学习。
下面我们着重介绍map的键值对存储和[]重载。


3.2 map的元素存储

在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:

  • typedef pair<const key, T> value_type;

文章开头我们简单地了解了下键值对,可以看出pair 是一个模板结构体,它包含两个值,分别称为 first 和 second,分别对应于键(Key)和值(Value)在 map 中的位置。

当你向 map 插入一个元素时,你实际上是在插入一个 std::pair<Key, Value> 对象。同样地,当你从 map 中检索元素时,你得到的是一个 std::pair<const Key, Value> 的引用(或迭代器指向的对象),其中 Key 是 const 的,因为 map 的键在插入后不应该被修改。


3.3 map的几种初始化方式

  • 创建有名对象
  • 使用匿名对象
  • 使用make_pair构建一个匿名对象
  • 隐式类型转换
int main()
{map<string, string> m;//创建有名对象pair<string, string> p("front", "前");m.insert(p);//使用匿名对象m.insert(pair<string, string>("behind", "后"));//使用make_pair构建一个匿名对象m.insert(make_pair("left", "左"));//隐式类型转换m.insert({ "right", "右" });for (const auto& e : m){cout << e.first << "->" << e.second << endl;}cout << endl;return 0;
}

在这里插入图片描述

从运行结果可以看出,我们插入的键值对是按照 “键”(英文单词)排序过的。

| 对其中make_pair隐式类型转换做如下解释:

  • make_pair是 C++ 标准库中的一个非常有用的函数模板,它定义在头文件<utility> 中,make_pair 的主要作用是创建一个 std::pair类型的对象
template <class T1,class T2>
pair<T1,T2> make_pair (T1 x, T2 y)
{return ( pair<T1,T2>(x,y) );
}
  • 使用make_pair的好处是可以自动推导类型,不需要我们指定了

  • 单参数的构造函数支持隐式类型转换,多参数也支持,只需要用{}括起来就可

除了以上的四种初始化方法,还有一种更为方便的方法。

| initializer_list:

C++11支持了使用initializer_list初始化列表来直接初始化map对象:

在这里插入图片描述
其中value_typepair<const key_type, mapped_type>的别名。

initializer_list是C++11标准中引入的一种新类型,它提供了一种统一且方便的方式来初始化对象,特别是用于构造函数和函数参数中,以允许传递一个初始化元素列表。

  • 它表示一个特定类型的值的数组,是一种轻量级的包装器,用于在编译时捕获花括号初始化的列表]
  • 提供了一种灵活且统一的方式来初始化对象和处理多个同类型值的列表
int main()
{map<string, string> m = { {"front", "前"},{"behind", "后"}, {"left", "左"},{"right", "右"} };//范围for遍历for (const auto& e : m){cout << e.first << "->" << e.second << endl;}cout << endl;//迭代器遍历map<string, string>::iterator it = m.begin();while (it != m.end()){cout << it->first << "->" << it->second << endl;++it;}return 0;
}

在这里插入图片描述

花括号外层是initializer_list,内层是隐式类型转换。


3.4 使用map计数

  • 假设我们需要统计字符出现的次数。

计数的规则是:key存储对应的字符,value为字符出现的次数。在map中找给定的字符,如果没找到就插入这个字符和出现的次数1;如果在map中找到了这个字符,我们就++对应的value。

这里简单介绍一下map中的find函数接口:find函数用于查找具有指定键的元素。如果找到了该元素,find函数会返回一个指向该元素的迭代器;如果没有找到,返回迭代器map::end()

void test1()
{char arr[] = { 'a','d','h','a','b','a','h','a','b','d','a','h','d','b','d' };map<char, int> m;for (auto ch : arr){map<char, int>::iterator it = m.find(ch);//没找到就插入if (it == m.end()){m.insert({ ch, 1 });}//找到就++对应的valueelse{++it->second;}}for (auto e : m){cout << e.first << "->" << e.second << endl;}
}

在这里插入图片描述

除了上面的计数方法,还有一种更为简单的方法也可以实现计数:

void test2()
{char arr[] = { 'a','d','h','a','b','a','h','a','b','d','a','h','d','b','d' };map<char, int> m;for (auto ch : arr){m[ch]++;}for (auto e : m){cout << e.first << "->" << e.second << endl;}
}

在这里插入图片描述

上面的计数实现依赖于map中重载了运算符[]。我们看到上面的实现过程似乎很简洁,那这个运算符重载究竟是怎么只用了一行简短的代码就实现了计数的呢?答案就在下面,我们接着往下看。


3.5 [ ]运算符重载

下面是运算符[]重载的函数原型:

在这里插入图片描述

  • mapped_type —> value
  • key_type —> key

简单来说[]的使用规则是传入key,返回对应value的引用。那要是传入的key在当前的map中没有呢?

如果map中没有key,则会插入一个由key和value(默认值)组成的键值对,最后返回刚插入的value的引用。

[]的调用等价于:

*((this->insert(make_pair(k,mapped_type()))).first)).second

是不是有点意外,[]的重载竟然不是复用find函数,而是复用insert函数。
[]重载实现的关键是利用了insert函数的返回值(前面想着map的函数接口和set差不多,打算偷懒不重复介绍了,看来前面欠的这里终归要还呜呜…),来看:

在这里插入图片描述
insert的返回值是一个迭代器,如果插入成功(map中原本没有key),则返回一个由指向新插入元素的迭代器和bool值(插入成功为true,失败为false) 组成的键值对;如果插入失败(map中原本有key),则返回一个由map中已存在元素的迭代器和bool值 组成的键值对。

然后.first访问到的是新插入的、或原本元素的迭代器,再解引用.second访问到的就是我们想要的key对应的value了。

头像

这里的逻辑有点绕,我大概画一下其中的指向关系:
在这里插入图片描述

简单总结就是:key存在,返回对应的value;key不存在,插入key和value(默认)。
看到这里相信我们就理解了上面调用[]重载计数的原理。

void test3()
{map<string, string> m;//插入m.insert(make_pair("front", "前"));//插入 <"behind", "">m["behind"];//插入+修改m["left"] = "左";//查找cout << m["right"] << endl;
}

虽然[]这样重载确实在某些场景方便了我们,但也存在不好的一面。比如我们原本想查找,但如果map中没有这个元素,那就会把这个元素插入进入。所以[]固然好用,但要谨慎使用哦!


4、multimap

4.1 multimap 介绍

  • multimap文档介绍
  • multimap也声明在头文件<map>

其实multimap也没什么可介绍的了,无非就是相比较与map,multimap允许键值冗余,再结合multisetmultimap无非也就那点东西喽。(被我逮到偷懒的时机了吧)
不过值得一说的是multimap没有再重载[],因为multmap的特点重载[]会使得其行为变得不明确。
还有就是从下面的实验可以得出multimapmultiset的erase函数接口特点是一样的。

void test4()
{multimap<string, string> mtm;mtm.insert({ "front", "前" });mtm.insert({ "behind", "后"});mtm.insert({ "left", "左" });mtm.insert({ "front", "前" });mtm.insert({ "behind", "后" });mtm.insert({ "front", "前" });mtm.insert({ "right", "右" });mtm.insert({ "left", "左" });mtm.insert({ "behind", "后" });mtm.insert({ "front", "前" });mtm.insert({ "left", "左" });for (const auto& e : mtm){cout << e.first << "->" << e.second << endl;}cout << endl;auto it = mtm.find("front");//传迭代器删除mtm.erase(it);for (const auto& e : mtm){cout << e.first << "->" << e.second << endl;}cout << endl;//传值删除mtm.erase("behind");for (const auto& e : mtm){cout << e.first << "->" << e.second << endl;}cout << endl;//传迭代器区间删除mtm.erase(mtm.equal_range("left").first, mtm.equal_range("left").second);for (const auto& e : mtm){cout << e.first << "->" << e.second << endl;}cout << endl;
}

请添加图片描述

如果multimap中存在多个key,则传迭代器只会删除一个,传值和传迭代器区间会将multimap中所有的key删除。


本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

在不受支持的 Mac 上安装 macOS Sequoia (OpenCore Legacy Patcher v2.0.1)

在不受支持的 Mac 上安装 macOS Sequoia (OpenCore Legacy Patcher v2.0.1) Install macOS on unsupported Macs 请访问原文链接&#xff1a;https://sysin.org/blog/install-macos-on-unsupported-mac/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主…

【CoppeliaSim V4.7】The Python interpreter could not handle the wrapper script

[sandboxScript:error] The Python interpreter could not handle the wrapper script (or communication between the launched subprocess and CoppeliaSim could not be established via sockets). Make sure that the Python modules ‘cbor2’ and ‘zmq’ are properly i…

【C++】stack和queue的使用及模拟实现

stack就是栈的意思&#xff0c;这个结构遵循后进先出(LIFO)的原则&#xff0c;可以将栈想象为一个子弹夹&#xff0c;先进去的子弹后出来。 queue就是队列的意思&#xff0c;这个结构遵循先进先出(FIFO)的原则&#xff0c;可以将对列想象成我们排队买饭的场景&#xff0c;先排…

Shopee 大促想爆单如何准备?EasyBoss ERP为你准备了一份攻略!

Shopee下半年第二个大促节点——10.10品牌大促即将来到&#xff0c;根据Shopee的官方的数据&#xff0c;9.9大促当天&#xff0c;Shopee Mall单量增至平日4倍。 老板们&#xff0c;准备好自己的热卖爆款冲击10.10大促了吗&#xff1f; 图源&#xff1a;Shopee 为助力大家迎战大…

大模型速通LLM神书来了《从头开始构建大型语言模型》,尚未发布,GitHub标星22k!!

这本大模型书籍资料已经上传CSDN&#xff0c;朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】 本书介绍 《从零构建大模型》是一本即将于今年10月底发布的书籍&#xff0c;github已经吸引了惊人的21.7k标星&#xff01;作者是威斯康星大学麦迪逊分…

N个utils(类加载-初始化-序列化)

fasterxml.jackson.databind.ObjectMapper(springboot本身就集成了) public class ObjectMapper {// 公共的ObjectMapper对象public static com.fasterxml.jackson.databind.ObjectMapper mapper new com.fasterxml.jackson.databind.ObjectMapper();/*** Description: 将数据…

推荐一款开源的链路监控系统

12.9k star&#xff0c;最强链路监控系统推荐&#xff0c;推荐 用过cat、pinpoint、skywalking等链路监控系统&#xff0c;各有优劣&#xff0c;但用的最多的还是pinpoint&#xff0c;工作6年&#xff0c;其中有4年都在用pinpoint&#xff0c;所以也比较熟悉&#xff0c;之前也…

鸿蒙界面开发——组件(10):单选框Radio复选框checkbox 下拉框select 多条件筛选Filter

单选框Radio 单选框一直会有这个圆圈&#xff0c;在选中和未选中之间切换状态。 Radio通过调用接口来创建&#xff0c;接口调用形式如下&#xff1a; Radio(options: RadioOptions) Radio(options: {value: string, group: string ,indicatorType:RadioIndicatorType,(新增) …

NET 7 AOT 的使用以及+NET 与 Go 互相调用

目录 背景 C# 部分 环境要求 创建一个控制台项目 体验 AOT 编译 C# 调用库函数 减少体积 C# 导出函数 C# 调用 C# 生成的 AOT Golang 部分 安装 GCC Golang 导出函数 .NET C# 和 Golang 互调 C# 调用 Golang Golang 调用 C# 其他 背景 其实&#xff0c;规划这篇文章有一段时间了…

AI产品经理必知的133个专业术语

一、机器学习与数据科学 1、监督学习&#xff08;Supervised Learning&#xff09; 监督学习是机器学习的一种形式&#xff0c;其中模型通过带标签的数据集进行训练。训练数据包括输入特征&#xff08;X&#xff09;和对应的输出标签&#xff08;Y&#xff09;&#xff0c;模…

哪个牌子的麦克风好?选购无线麦克风必看的五大隐藏风险

随着短视频行业的兴起。短视频已经成为我们日常生活的一个重要表达载体&#xff0c;同时无线麦克风也是正式进入到了我们的视野之中&#xff0c;这种麦克风凭借没有线材束缚、兼容性更好、拾音更好的特性&#xff0c;成为了不少短视频创作者必不可少的“搭档之一”&#xff0c;…

uniapp APP自动更新组件

在uniapp中实现APP自动更新功能&#xff0c;主要涉及到客户端在功能不断迭代过程中&#xff0c;需要进行自动更新。uniapp一个详细的实现步骤&#xff0c;包括客户端和服务器端的配置&#xff1a; 服务器端配置 版本信息管理 服务器端需要维护一个数据库或配置文件&#xff…

C语言-动态内存分配讲解

目录 ✨1.什么是动态内存分配 &#x1f495;2.动态内存开辟函数 malloc ✨3.malloc函数的检查&#xff08;两种方法&#xff09; &#x1f495;4.动态内存释放函数 free ✨5.free 函数接收空指针 ✨6.为什么要释放动态内存 &#x1f495;7.动态内存开辟函数calloc &#…

【优选算法之位运算】No.7--- 经典位运算算法

文章目录 前言一、位运算几种模型&#xff1a;1.1 基础的位运算&#xff1a; << >> ~ & | ^1.2 几种模型&#xff1a;1.3 模型练习 二、位运算示例&#xff1a;2.1 判定字符是否唯⼀2.2 丢失的数字2.3 两整数之和2.4 只出现⼀次的数字 II2.5 消失的两个数字 前…

STM32G474使用DMA和SPI1实现自发自收

STM32G474使用DMA搬运数据&#xff0c;实现SPI自发自收&#xff0c;验证SPI收发是否正常。测试时&#xff0c;需要将SPI1_MISO和SPI1_MOSI短接。SPI1外设用作主机&#xff0c;其接口&#xff1a;将SPI1_SCK映射到PA5,SPI1_MISO映射到PA6,SPI1_MOSI映射到PA7,SPI1_NSS映射到PA4。…

基于PHP+MySQL组合开发地方门户分类信息网站源码系统 带完整的安装代码包以及搭建部署教程

系统概述 随着互联网技术的飞速发展&#xff0c;地方门户分类信息网站逐渐成为城市生活不可或缺的一部分。它们涵盖了房产、招聘、二手交易、生活服务等多个领域&#xff0c;为当地居民提供了全方位的信息服务。为了满足这一市场需求&#xff0c;我们开发了这款基于PHPMySQL的…

2015年国赛高教杯数学建模A题太阳影子定位解题全过程文档及程序

2015年国赛高教杯数学建模 A题 太阳影子定位 技术就是通过分析视频中物体的太阳影子变化&#xff0c;确定视频拍摄的地点和日期的一种方法。   1.建立影子长度变化的数学模型&#xff0c;分析影子长度关于各个参数的变化规律&#xff0c;并应用你们建立的模型画出2015年10月…

Maxim(美信)—MAX20079AATP/VY PMIC芯片详解

写在前面 本系列文章主要讲解Maxim&#xff08;美信&#xff09;—MAX20079AATP/VY PMIC芯片的相关知识&#xff0c;希望能帮助更多的同学认识和了解MAX20079AATP/VY芯片。 若有相关问题&#xff0c;欢迎评论沟通&#xff0c;共同进步。(*^▽^*) PMIC是Power Management Int…

自动驾驶系列—盲点检测(BSD)功能:智能驾驶安全的关键保障

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

Spring Cloud :Hystrix实现优雅的服务容错

目录 Hystrix概述&#xff1a;第一个Hystrix程序步骤1&#xff1a;创建父工程hystrix-1步骤2&#xff1a;改造服务提供者步骤3&#xff1a;改造服务消费者为Hystrix客户端&#xff08;1&#xff09;添加Hystrix依赖&#xff08;2&#xff09;添加EnableHystrix注解&#xff08;…