C++——map和set的使用以及map系列

目录

map和set的使用

1. 序列式容器和关联式容器

2. set系列的使⽤

2.1 set和multiset参考⽂档

2.2 set类的介绍

2.3 set的构造和迭代器

2.4 set的增删查

set的增删查关注以下⼏个接⼝即可:

2.6 find和erase使⽤样例:

lower_bound(); upper_bound();

2.7 multiset和set的差异(可重复set(multiset))

那么到这里来一个set使用的例题

下一题,环形链表也超简单。

3. map系列的使⽤

3.1 map和multimap参考⽂档

3.2 map类的介绍

3.3 pair类型介绍

3.4 map的构造

3.5 map的增删查

3.6 map的数据修改

3.7 构造遍历及增删查使⽤样例

3.8 map的迭代器和[]功能样例:

利用operator[] 来统计水果出现的次数

3.9 multimap和map的差异

最后,来看一个运用列题:

总结:第一次做的时候总想着自己创建一个头节点,然后把整个链表跟它一样先把所有next串起来再进行查找,可是看完题解后,别人全用hash存起来后在进行连接是真的方便。


map和set的使用

1. 序列式容器和关联式容器

前⾯我们已经接触过STL中的部分容器如:string、vector、list、deque、list等,这 些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间⼀般没有紧密的关联关系,⽐如交换⼀下,他依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。
关联式容器也是⽤来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是⾮线性结构,两个位置有紧密的关联关系,交换⼀下,他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。
本章节讲解的map和set底层是红⿊树,红⿊树是⼀颗平衡⼆叉搜索树。set是key搜索场景的结构,map是key/value搜索场景的结构。

2. set系列的使⽤

2.1 set和multiset参考⽂档

https://legacy.cplusplus.com/reference/set/

2.2 set类的介绍

set的声明如下,T就是set底层关键字的类型
set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模版参数
•  set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参数。
⼀般情况下,我们都不需要传后两个模版参数
set底层是⽤红⿊树实现,增删查效率是O ( logN ) ,迭代器遍历是⾛的搜索树的中序,所以是有序的。
前⾯部分我们已经学习了vector / list等容器的使⽤,STL容器接⼝设计,⾼度相似,所以这⾥我们就不再⼀个接⼝⼀个接⼝的介绍,⽽是直接带着⼤家看⽂档,挑⽐较重要的接⼝进⾏介绍。
template < class T, // set::key_type/value_typeclass Compare = less<T>, // set::key_compare/value_compareclass Alloc = allocator<T>, // set::allocator_type> class set;

2.3 set的构造和迭代器

set的构造我们关注以下⼏个接⼝即可。
set的⽀持正向和反向迭代遍历,遍历默认按升序顺序,因为底层是⼆叉搜索树迭代器遍历⾛的中序;⽀持迭代器就意味着⽀持范围for,set的iterator和const_iterator都 不⽀持迭代器修改数据 修改关键字数据,破坏了底层搜索树的结构
// empty (1) ⽆参默认构造
explicit set (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());// range (2) 迭代器区间构造
template <class InputIterator>
set (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& = allocator_type());// copy (3) 拷⻉构造
set (const set& x);// initializer list (5) initializer 列表构造
set (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.4 set的增删查

set的增删查关注以下⼏个接⼝即可:

// 单个数据插⼊,如果已经存在则插⼊失败
pair<iterator,bool> insert (const value_type& val);

int main()
{set<int> s;s.insert(1);s.insert(2);s.insert(3);s.insert(4);auto it = s.begin();while (it != s.end()){cout << *it << " ";it++;}return 0;
}

// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
int main()
{set<int> s;s.insert(1);s.insert(2);s.insert(3);s.insert(3);s.insert(4);auto it = s.begin();while (it != s.end()){cout << *it << " ";it++;}return 0;
}

// 查找val,返回val所在的迭代器,没有找到返回end()
iterator find (const value_type& val);
auto it = s.find(3);
cout << *it << endl;

// 查找val,返回Val的个数
size_type count (const value_type& val) const;
因为set具有去重的能力,那么count就可以用来判断是否存在这个val
	cout << s.count(3) << endl;

// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);

这里注意不能再while里面删除后再之间访问,会造成迭代器失效,要么就删除一个,然后再将这个迭代器赋值给it 

// 删除val,val不存在返回0,存在返回1
size_type erase (const value_type& val);

s.erase(3);
auto it = s.begin();
while (it != s.end())
{cout << *it << " ";it++;
}

// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);

左闭右开区间,那么就删除[2,5)之间的值,但不会删除5 

auto first = s.find(2);
auto end = s.find(5);
s.erase(first, end);
auto it = s.begin();
while (it != s.end())
{cout << *it << " ";it++;
}

// 返回⼤于等于val位置的迭代器
iterator lower_bound (const value_type& val) const;

// 返回⼤于val位置的迭代器
iterator upper_bound (const value_type& val) const;

//10 20 30 40 50 60 //>=25 那么就是从30开始
auto first = s.lower_bound(25); //>55的迭代器,那么就是60
auto end = s.upper_bound(55);
s.erase(first, end);
auto it = s.begin();
while (it != s.end())
{cout << *it << " ";it++;
}
//10 20 60

2.5. insert和迭代器遍历使⽤样例:
#include<iostream>
#include<set>
using namespace std;
int main()
{// 去重+升序排序set<int> s;// 去重+降序排序(给⼀个⼤于的仿函数)//set<int, greater<int>> s;s.insert(5);s.insert(2);s.insert(7);s.insert(5);//set<int>::iterator it = s.begin();auto it = s.begin();while (it != s.end()){// error C3892: “it”: 不能给常量赋值// *it = 1;cout << *it << " ";++it;}cout << endl;// 插⼊⼀段initializer_list列表值,已经存在的值插⼊失败s.insert({ 2,8,3,9 });for (auto e : s){cout << e << " ";}cout << endl;set<string> strset = { "sort", "insert", "add" };// 遍历string⽐较ascll码⼤⼩顺序遍历的for (auto& e : strset){cout << e << " ";}cout << endl;
}

2.6 find和erase使⽤样例:

#include<iostream>
#include<set>
using namespace std;
int main()
{set<int> s = { 4,2,7,2,8,5,9 };for (auto e : s){cout << e << " ";}cout << endl;// 删除最⼩值s.erase(s.begin());for (auto e : s){cout << e << " ";}cout << endl;// 直接删除xint x;cin >> x;int num = s.erase(x);if (num == 0){cout << x << "不存在!" << endl;}for (auto e : s){cout << e << " ";}cout << endl;// 直接查找在利⽤迭代器删除xcin >> x;auto pos = s.find(x);if (pos != s.end()){s.erase(pos);}else{cout << x << "不存在!" << endl;}for (auto e : s){cout << e << " ";}cout << endl;// 算法库的查找 O(N)auto pos1 = find(s.begin(), s.end(), x);// set⾃⾝实现的查找 O(logN)auto pos2 = s.find(x);// 利⽤count间接实现快速查找cin >> x;if (s.count(x)){cout << x << "在!" << endl;}else{cout << x << "不存在!" << endl;}return 0;
}

lower_bound(); upper_bound();

#include<iostream>
#include<set>
using namespace std;
int main()
{std::set<int> myset;for (int i = 1; i < 10; i++)myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90for (auto e : myset){cout << e << " ";}cout << endl;// 实现查找到的[itlow,itup)包含[30, 60]区间// 返回 >= 30auto itlow = myset.lower_bound(30);// 返回 > 60auto itup = myset.upper_bound(60);// 删除这段区间的值myset.erase(itlow, itup);for (auto e : myset){cout << e << " ";}cout << endl;return 0;
}

2.7 multiset和set的差异(可重复set(multiset))

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

那么到这里来一个set使用的例题

怎么样这题是不是超简单~
只需要进行去重,然后看一个数组的元素是否再另一个数组里出现。那么就要用set去重很方便。
class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {set<int> s;for(auto e : nums1){s.insert(e);}set<int> st;for(auto e : nums2){st.insert(e);}vector<int> v;//只是在遍历s中的每一个元素 与st中的每一个元素进行比较for(auto e:s){if(st.find(e)!=st.end()){v.push_back(e);}}return v;}
};

下一题,环形链表也超简单。

我记得只学C语言的时候,那个时候用快慢双指针来找规律,用快指针去追慢指针,那么这个时候就会发现是否存在环,但是这种办法太慢,要思考很仔细,如果你用set来进行判断,每次都添加节点,如果有一次下一个节点在里面存在就说明有环,否则就没有,就变得非常简单。
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head) {unordered_map<ListNode*,int> hash;ListNode* root=head;while(root){hash[root]++;if(hash[root]==2) return root;root=root->next;}return root;}
};

3. map系列的使⽤

3.1 map和multimap参考⽂档

https://legacy.cplusplus.com/reference/map/

3.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;

3.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){}
};template <class T1, class T2>
inline pair<T1, T2> make_pair(T1 x, T2 y)
{return (pair<T1, T2>(x, y));
}

3.4 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();

3.5 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;

3.6 map的数据修改

前⾯我提到map⽀持修改mapped_type 数据,不⽀持修改key数据,修改关键字数据,破坏了底层搜索树的结构。
map第⼀个⽀持修改的⽅式时通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map还有⼀个⾮常重要的修改接⼝operator[],但是operator[]不仅仅⽀持修改,还⽀持插⼊数据和查找数据,所以他是⼀个多功能复合接⼝需要注意从内部实现⻆度,map这⾥把我们传统说的value值,给的是T类型,typedef为mapped_type。⽽value_type是红⿊树结点中存储的pair键值对值。⽇常使⽤我们还是习惯将这⾥的T映射值叫做value

operator[] 很重要,在各类算法题里都常常用到。

Member types
key_type->The first template parameter(Key)
mapped_type->The second template parameter(T)
value_type->pair<const key_type, mapped_type>
// 查找k,返回k所在的迭代器,没有找到返回end(),如果找到了通过iterator可以修改key对应的
mapped_type值
iterator find(const key_type& k);
// ⽂档中对insert返回值的说明
// The single element versions (1) return a pair, with its member pair::first
//set to an iterator pointing to either the newly inserted element or to the
//element with an equivalent key in the map.The pair::second element in the pair
//is set to true if a new element was inserted or false if an equivalent key
//already existed.
// insert插⼊⼀个pair<key, T>对象
// 1、如果key已经在map中,插⼊失败,则返回⼀个pair<iterator,bool>对象,返回pair对象
//first是key所在结点的迭代器,second是false
// 2、如果key不在在map中,插⼊成功,则返回⼀个pair<iterator,bool>对象,返回pair对象
//first是新插⼊key所在结点的迭代器,second是true
// 也就是说⽆论插⼊成功还是失败,返回pair<iterator,bool>对象的first都会指向key所在的迭
//代器
// 那么也就意味着insert插⼊失败时充当了查找的功能,正是因为这⼀点,insert可以⽤来实现operator[]
// 需要注意的是这⾥有两个pair,不要混淆了,⼀个是map底层红⿊树节点中存的pair<key, T>,另
//⼀个是insert返回值pair<iterator, bool>
pair<iterator, bool> insert(const value_type & val);
mapped_type& operator[] (const key_type& k);
// operator的内部实现
mapped_type& operator[] (const key_type& k)
{// 1、如果k不在map中,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储
//	mapped_type值的引⽤,那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊ + 修改功能// 2、如果k在map中,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的//迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找 + 修改的功能pair<iterator, bool> ret = insert({ k, mapped_type() });iterator it = ret.first;return it->second;
}
// 1 、如果 k 不在 map 中, insert 会插⼊ k mapped_type 默认值,同时 [] 返回结点中存储
mapped_type 值的引⽤,那么我们可以通过引⽤修改返映射值。所以 [] 具备了插⼊ + 修改功能
// 2 、如果 k map 中, insert 会插⼊失败,但是 insert 返回 pair 对象的 first 是指向 key 结点的
迭代器,返回值同时 [] 返回结点中存储 mapped_type 值的引⽤,所以 [] 具备了查找 + 修改的功能

3.7 构造遍历及增删查使⽤样例

#include<iostream>
#include<map>
using namespace std;
int main()
{// initializer_list构造及迭代遍历map<string, string> dict = { {"left", "左边"}, {"right", "右边"},{"insert", "插⼊"},{ "string", "字符串" } };//map<string, string>::iterator it = dict.begin();auto it = dict.begin();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;// insert插⼊pair对象的4种⽅式,对⽐之下,最后⼀种最⽅便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", "左边,剩余" });// 范围for遍历for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}cout << endl;string str;while (cin >> str){auto ret = dict.find(str);if (ret != dict.end()){cout << "->" << ret->second << endl;}else{cout << "⽆此单词,请重新输⼊" << endl;}}// erase等接⼝跟set完全类似,这⾥就不演⽰讲解了return 0;
}

3.8 map的迭代器和[]功能样例:

利用迭代器进行记录水果次数
#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[] 来统计水果出现的次数

#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{// 利⽤[]插⼊+修改功能,巧妙实现统计⽔果出现的次数string arr[] = { "苹果", "西⽠", "苹果", "西⽠", "苹果", "苹果", "西⽠","苹果", "⾹蕉", "苹果", "⾹蕉" };map<string, int> countMap;for (const auto& str : arr){// []先查找⽔果在不在map中// 1、不在,说明⽔果第⼀次出现,则插⼊{⽔果, 0},同时返回次数的引⽤,++⼀下就变成1次了// 2、在,则返回⽔果对应的次数++countMap[str]++;}for (const auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;return 0;
}
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{map<string, string> dict;dict.insert(make_pair("sort", "排序"));// key不存在->插⼊ {"insert", string()}dict["insert"];// 插⼊+修改dict["left"] = "左边";// 修改dict["left"] = "左边、剩余";// key存在->查找cout << dict["left"] << endl;return 0;
}

3.9 multimap和map的差异

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

最后,来看一个运用列题:

就是将整个链表的next 和 random全都丢入hash表里面,然后创建新的链表,每次连接链表的next 和 random全都再hash表里面进行查找即可,这一题是对哈希表最好的灵活运用用map或unordered_map 都行。

/*
// Definition for a Node.
class Node {
public:int val;Node* next;Node* random;Node(int _val) {val = _val;next = NULL;random = NULL;}
};
*/class Solution {
public:Node* copyRandomList(Node* head) {if(head==nullptr) return nullptr;unordered_map<Node*,Node*> hash;Node* cur=head;while(cur){hash[cur]=new Node(cur->val);cur=cur->next;}cur=head;while(cur){hash[cur]->next=hash[cur->next];hash[cur]->random=hash[cur->random];cur=cur->next;}return hash[head];}
};

总结:第一次做的时候总想着自己创建一个头节点,然后把整个链表跟它一样先把所有next串起来再进行查找,可是看完题解后,别人全用hash存起来后在进行连接是真的方便。

总结一下吧~该节只是对set/map简单的结束和运用,对于这两个数据结构来刷算法是完全够用了,对我的作用很大,希望对你也是!!!

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

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

相关文章

如何选择OS--Linux不同Distribution的选用

写在前言&#xff1a; 刚写了Windows PC的不同editions的选用&#xff0c;趁热&#xff0c;把Linux不同的Distribution选用也介绍下&#xff0c;希望童鞋们可以了解-->理解-->深入了解-->深入理解--...以致于能掌握特定版本的Linux的使用甚者精通。……^.^…… so&a…

项目文件配置

1. 参数配置化 1.1 问题分析 1.2 问题解决 Value 注解通常用于外部配置的属性注入&#xff0c;具体用法为&#xff1a;Value("${配置文件中的key}") 2. yml配置文件 2.1 SpringBoot提供了多种属性配置方式 2.2 常见配置文件格式对比 2.3 yml 基本语法 大小写敏…

实时美颜的技术突破:视频美颜SDK与直播美颜工具的开发详解

如今&#xff0c;视频美颜SDK和直播美颜工具的开发&#xff0c;为各类应用提供了技术支持&#xff0c;使得美颜效果更加智能、高效。本文将详细探讨实时美颜的技术突破及其在视频美颜SDK和直播美颜工具中的应用与开发。 一、视频美颜SDK的核心技术 1.人脸检测与特征点识别 视…

HObject复制耗时试用

测试源码一 //第一步const int N 1000;HObject[] imgs new HObject[N];for (int i 0; i < N; i){HOperatorSet.GenImageConst(out imgs[i], "byte", 1024 i, 1024 i);}//第二步List<HObject> lists new List<HObject>();for(int i 0; i < …

OpenCV特征检测(3)计算图像中每个像素处的特征值和特征向量函数cornerEigenValsAndVecs()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算图像块的特征值和特征向量用于角点检测。 对于每一个像素 p &#xff0c;函数 cornerEigenValsAndVecs 考虑一个 blockSize blockSize 的邻…

[Spring]Spring MVC 请求和响应及用到的注解

文章目录 一. Maven二. SpringBoot三. Spring MVC四. MVC注解1. RequestMapping2. RequestParam3. PathVariable4. RequestPart5. CookieValue6. SessionAttribute7. RequestHeader8. RestController9. ResponseBody 五. 请求六. 响应 一. Maven Maven是⼀个项⽬管理⼯具。基于…

JavaScript发送邮件:实现前端触发的教程?

JavaScript发送邮件的方式&#xff1f;怎么使用JavaScript发信&#xff1f; 无论是用户反馈、联系表单还是自动通知&#xff0c;前端触发的邮件发送功能都能极大地提升用户体验。AokSend将详细介绍如何通过JavaScript发送邮件&#xff0c;实现前端触发的邮件发送功能。 JavaS…

力扣 438找到字符串中所有字母异位词

https://leetcode.cn/problems/find-all-anagrams-in-a-string/ 题目描述 题目分析 异位词所表示的空间 P \text{P} P 即一字符串的所有排列,记 s i \bold{s_i} si​为以 s [ i ] s[i] s[i]开头的长度为 plen \text{plen} plen的 s s s子串 故本题可理解为求解 A n s Ans Ans…

LabVIEW提高开发效率技巧----采用并行任务提高性能

在复杂的LabVIEW开发项目中&#xff0c;合理利用并行任务可以显著提高系统的整体性能和响应速度。并行编程是一种强大的技术手段&#xff0c;尤其适用于实时控制、数据采集以及多任务处理等场景。LabVIEW的数据流编程模型天然支持并行任务的执行&#xff0c;结合多核处理器的硬…

Toon Dinosaurs 2 可爱卡通恐龙怪物模型带动画

剑龙、甲龙、厚头龙、副龙、二龙和腕龙使用(根运动)动画文件绘制人物。 动画: 空闲+随机空闲动画跳跃(跳跃、跌倒、落地)。 3攻击 2个被击中,1个死亡和1个起床动画。 咆哮 左转和右转。跑,跑,转身。 最近添加:向前走,转身走。 查看视频以观看动画! 近似三角形计数:…

读构建可扩展分布式系统:方法与实践10最终一致性

1. 最终一致性 1.1. 在一些应用领域&#xff0c;通常谈论的是银行和金融行业&#xff0c;最终一致性根本不合适 1.2. 事实上&#xff0c;最终一致性在银行业已经使用了很多年 1.2.1. 支票需要几天时间才能在你的账户上进行核对&#xff0c;而且你可以轻松地开出比账户余额多的…

网络基础,协议,OSI分层,TCP/IP模型

网络的产生是数据交流的必然趋势&#xff0c;计算机之间的独立的个体&#xff0c;想要进行数据交互&#xff0c;一开始是使用磁盘进行数据拷贝&#xff0c;可是这样的数据拷贝效率很低&#xff0c;于是网络交互便出现了&#xff1b; 1.网络是什么 网络&#xff0c;顾名思义是…

oracle数据库启动

文章目录 背景一、步骤1.登录oracle用户2.启动监听服务3.启动数据库 背景 oracle数据库启动 一、步骤 1.登录oracle用户 代码如下&#xff08;示例&#xff09;&#xff1a; su - oracle2.启动监听服务 代码如下&#xff08;示例&#xff09;&#xff1a; lsnrctl start成…

生信初学者教程(四):软件

文章目录 RRstudioLinux系统其他软件本书是使用R语言编写的教程,用户需要下载R和RStudio软件用于进行分析。 版权归生信学习者所有,禁止商业和盗版使用,侵权必究 R R语言是一种免费的统计计算和图形化编程语言,是一种用于数据分析和统计建模的强大工具。它具有丰富的统计…

C++11——lambda

lambda lambda的介绍lambda的使用lambda的细节->捕捉列表 lambda的介绍 lambda是匿名函数&#xff0c;再适合的场景去使用可以提高代码的可读性。 场景&#xff1a; 假设有一个Goods类需要进行按照价格、数量排序 class Goods {string name;size_t _price;//价格int num;/…

【IoTDB 线上小课 07】多类写入接口,快速易懂的“说明书”!

【IoTDB 视频小课】稳定更新中&#xff01;第七期来啦~ 关于 IoTDB&#xff0c;关于物联网&#xff0c;关于时序数据库&#xff0c;关于开源... 一个问题重点&#xff0c;3-5 分钟&#xff0c;我们讲给你听&#xff1a; 一条视频了解写入接口 了解我们的友友们&#xff0c;应该…

我的AI工具箱Tauri版-VideoClipMixingCut视频批量混剪

本教程基于自研的AI工具箱Tauri版进行VideoClipMixingCut视频批量混剪。 VideoClipMixingCut视频批量混剪 是自研AI工具箱Tauri版中的一款强大工具&#xff0c;专为自动化视频批量混剪设计。该模块通过将预设的解说文稿与视频素材进行自动拼接生成混剪视频&#xff0c;适合需要…

关于http的206状态码和416状态码的意义、断点续传以及CORS使用Access-Control-Allow-Origin来允许跨域请求

一、关于http的206状态码和416状态码的意义及断点续传 HTTP 2xx范围内的状态码表明客户端发送的请求已经被服务器接受并且被成功处理了,HTTP/1.1 206状态码表示客户端通过发送范围请求头Range抓取到了资源的部分数据&#xff0c;一般用来解决大文件下载问题&#xff0c;一般CDN…

小小扑克牌算法

1.定义一个扑克牌类Card&#xff1a; package democard; public class Card {public String suit;//表示花色public int rank;//表示牌点数Overridepublic String toString() {return "{"suit rank"}";}//实例方法&#xff0c;初始化牌的点数和花色public…

Xinstall助力App推广,下载自动绑定提升转化率

在App推广和运营的过程中&#xff0c;我们经常会遇到一些痛点。比如&#xff0c;用户下载App后需要手动进行一系列繁琐的操作才能完成注册和绑定&#xff0c;这不仅影响了用户体验&#xff0c;还降低了转化率。那么&#xff0c;有没有一种方法能够简化这个过程&#xff0c;提升…