【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_type
           class Compare = less<T>,        // set::key_compare/value_compare
           class 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给值时会删除所有的x
	s.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_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class 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++三大特性之继承。大家自己好好消化!今天就分享到这!感谢各位的耐心垂阅!咱们下期见!拜拜~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最新AI自动无人智享直播系统 —— 视频自动播软件热门之选

在当今数字化浪潮汹涌澎湃的时代&#xff0c;直播行业正经历着前所未有的变革与创新。而最新的 AI 自动无人智享直播系统&#xff0c;无疑成为了视频自动播软件中的热门之选&#xff0c;正引领着直播领域迈向新的高度。 这款 AI 自动无人智享直播系统&#xff0c;其核心优势在于…

气膜球幕:科技与艺术的完美融合,沉浸式体验引领未来—轻空间

在现代化展览和活动中&#xff0c;如何突破传统展示方式&#xff0c;吸引观众的目光&#xff0c;带来前所未有的沉浸式体验&#xff1f;气膜球幕作为一种创新的科技展示平台&#xff0c;凭借其独特的球形结构和多功能应用&#xff0c;正在成为各大展览、活动和娱乐项目的首选。…

计算机视觉硬件知识点整理六:工业相机选型

文章目录 前言一、工业数字相机的分类二、相机的主要参数三、工业数字摄像机主要接口类型四、选择工业相机的考量因素六、实例分析 前言 随着科技的不断进步&#xff0c;工业自动化领域正经历着前所未有的变革。作为工业自动化的重要组成部分&#xff0c;工业相机在工业检测、…

Mysql读写分离分库分表

读写分离 什么是读写分离 读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 这样的话&#xff0c;就能够小幅提升写性能&#xff0c;大幅提升读性能。一般情况下&#xff0c;我们都会选择一主多从&#xff0c;也就是一台主数据库负责写&#xff0c;其他的从…

【C语言】结构体(四)

本篇重点是typedef关键字 一&#xff0c;是什么&#xff1f; typedef用来定义新的数据类型&#xff0c;通常typedef与结构体的定义配合使用。 简单来说就是取别名 ▶ struct 是用来定义新的数据类型——结构体 ▶ typedef是给数据类型取别名。 二&#xff0c;为什么&#xf…

普中51单片机——LED流水灯模块

1、GPIO概念 GPIO&#xff08;general purpose intput output&#xff09;是通用输入输出端口的简称&#xff0c;可以通过软件来控制其输入和输出。51 单片机芯片的 GPIO 引脚与外部设备连接起来&#xff0c;从而实现与外部通讯、 控制以及数据采集的功能。 1.1、GPIO分类 &a…

Linux入门系列--压缩与解压

一、前言 为了使传输的文件大小尽可能地小&#xff0c;我们采用压缩的方式生成压缩文件&#xff0c;然后将压缩包传输过去就可以了。衡量压缩方法地好坏主要有两点综合考量&#xff1a;一是压缩速度&#xff0c;二是压缩程度。很好理解&#xff0c;压缩一个文件&#xff0c;我…

云服务器重装系统后 一些报错与解决[ vscode / ssh / 子用户]

碰见的三个问题&#xff1a; 1.vscode连接失败 2.登录信息配置 3.新建子用户的一些设置 思考&#xff1a;遇见问题&#xff0c;第一反应 应该如何解决 目录 1. 错误 解决方法 原因 步骤 1&#xff1a;找到known_hosts文件并编辑 步骤 2&#xff1a;通过VSCode终端输入…

【包教包会】CocosCreator3.x——重写Sprite,圆角、3D翻转、纹理循环、可合批调色板、不影响子节点的位移旋转缩放透明度

一、效果演示 重写Sprite组件&#xff0c;做了以下优化&#xff1a; 1、新增自变换&#xff0c;在不影响子节点的前提下位移、旋转、缩放、改变透明度 新增可合批调色板&#xff0c;支持色相、明暗调节 新增圆角矩形、3D透视旋转、纹理循环 所有功能均支持合批、原生平台&…

南昌榉之乡托养机构解读:自闭症与看电视并无必然联系

在探讨自闭症的成因时&#xff0c;有人会问&#xff1a;自闭症是多看电视引起的吗&#xff1f;今天&#xff0c;就让我们来看看南昌榉之乡托养机构对此有何见解。 榉之乡大龄自闭症托养机构在江苏、广东、江西等地都有分校&#xff0c;一直致力于为大龄自闭症患者提供专业的支持…

卷积神经网络(CNN)的层次结构

卷积神经网络&#xff08;CNN&#xff09;是一种以其处理图像和视频数据的能力而闻名的深度学习模型&#xff0c;其基本结构通常包括以下几个层次&#xff0c;每个层次都有其特定的功能和作用&#xff1a; 1. 输入层&#xff08;Input Layer&#xff09;&#xff1a; 卷积神经网…

Milvus×OPPO:如何构建更懂你的大模型助手

01. 背景 AI业务快速增长下传统关系型数据库无法满足需求。 2024年恰逢OPPO品牌20周年&#xff0c;OPPO也宣布正式进入AI手机的时代。超千万用户开始通过例如通话摘要、新小布助手、小布照相馆等搭载在OPPO手机上的应用体验AI能力。 与传统的应用不同的是&#xff0c;在AI驱动的…

数据结构之二叉树详解:从原理到实现

1. 什么是二叉树&#xff1f; 二叉树&#xff08;Binary Tree&#xff09;是一种树形数据结构&#xff0c;其中每个节点最多有两个子节点&#xff0c;分别被称为左子节点和右子节点。二叉树可以用来表示层次关系&#xff0c;如文件目录、组织结构&#xff0c;或用于快速查找、…

CTF-PWN: WEB_and_PWN [第一届“吾杯”网络安全技能大赛 Calculator] 赛后学习(不会)

附件 calculate.html <!DOCTYPE html> <html lang"en"> <head><!-- 设置字符编码为 UTF-8&#xff0c;支持多语言字符集 --><meta charset"UTF-8"><!-- 设置响应式视图&#xff0c;确保页面在不同设备上自适应显示 --&…

用于LiDAR测量的1.58um单芯片MOPA(一)

--翻译自M. Faugeron、M. Krakowski1等人2014年的文章 1.简介 如今&#xff0c;人们对高功率半导体器件的兴趣日益浓厚&#xff0c;这些器件主要用于遥测、激光雷达系统或自由空间通信等应用。与固态激光器相比&#xff0c;半导体器件更紧凑且功耗更低&#xff0c;这在低功率供…

【maven-5】Maven 项目构建的生命周期:深入理解与应用

1. 生命周期是什么 ​在Maven出现之前&#xff0c;项目构建的生命周期就已经存在&#xff0c;软件开发人员每天都在对项目进行清理&#xff0c;编译&#xff0c;测试及部署。虽然大家都在不停地做构建工作&#xff0c;但公司和公司间&#xff0c;项目和项目间&#xff0c;往往…

数字时代的文化宝库:存储技术与精神生活

文章目录 1. 文学经典的数字传承2. 音乐的无限可能3. 影视艺术的数字化存储4. 结语 数字时代的文化宝库&#xff1a;存储技术与精神生活 在数字化的浪潮中&#xff0c;存储技术如同一座桥梁&#xff0c;连接着过去与未来&#xff0c;承载着人类文明的瑰宝。随着存储容量的不断增…

STM32标准库-FLASH

FLASH模仿EEPROM STM32本身没有自带EEPROM&#xff0c;但是自带了FLASH存储器。 STM32F103ZET6自带 1M字节的FLASH空间&#xff0c;和 128K64K的SRAM空间。 STM32F4 的 SPI 功能很强大&#xff0c;SPI 时钟最高可以到 37.5Mhz&#xff0c;支持 DMA&#xff0c;可以配置为 SPI协…

重学设计模式-工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)

在平常的学习和工作中&#xff0c;我们创建对象一般会直接用new&#xff0c;但是很多时候直接new会存在一些问题&#xff0c;而且直接new会让我们的代码变得非常繁杂&#xff0c;这时候就会巧妙的用到设计模式&#xff0c;平常我们通过力扣学习的算法可能并不会在我们工作中用到…

linux(centos) 环境部署,安装JDK,docker(mysql, redis,nginx,minio,nacos)

目录 1.安装JDK (非docker)1.1 将文件放在目录下&#xff1a; /usr/local/jdk1.2 解压至当前目录1.3 配置环境变量 2.安装docker2.1 验证centos内核2.2 安装软件工具包2.3 设置yum源2.4 查看仓库中所有docker版本&#xff0c;按需选择安装2.5 安装docker2.6 启动docker 并 开机…