set和map + multiset和multimap(使用+封装(RBTree))

set和map

  • 前言
  • 一、使用
    • 1. set
      • (1)、模板参数列表
      • (2)、常见构造
      • (3)、find和count
      • (4)、insert和erase
      • (5)、iterator
      • (6)、lower_bound和upper_bound
    • 2. multiset
    • 3. map
      • (1)、模板参数列表
      • (2)、构造
      • (3)、modifiers和operations
      • (4)、operator[]
    • 4. multimap
  • 二、封装
    • RBTree
      • 迭代器原理
      • RBTree实现代码
    • map
    • set
  • 三、总结

前言

本文介绍的是树型关联式容器。
关联式容器:用来存储数据,存储的是<key, value>结构的键值对,在检索时效率更高。主要有这四种:map,set,multimap,multiset。

键值对:用来标识具有一一对应关系的结构,该结构一般包含两个成员变量key和value,key表示键值,value表示与key对应的信息。

SGI—STL中关于键值对的定义:

//pair底层
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){}
};

一、使用

1. set

(1)、模板参数列表

模板参数列表

(2)、常见构造

void test_constructor()
{set<int> s1;                            //无参构造int arr[] = { 10,20,30,40,50 };set<int> s2(arr, arr + 5);              //数组范围构造set<int> s3(s2.begin(), s2.end());      //迭代器区间构造set<int> s4(s3);                        //拷贝构造
}

(3)、find和count

void test_find()
{set<int> s;s.insert(5);s.insert(10);s.insert(8);s.insert(2);//find return value: iterator(val is found)//otherwise set::end if (s.find(5) != s.end()){cout << "find:找到了" << endl;      }//count return value:1 (val is found),or 0 otherwiseif (s.count(5)){cout << "count:找到了" << endl;     }
}

(4)、insert和erase

void test_modify()
{//insert//去重+排序set<int> s;s.insert(10);s.insert(5);s.insert(6);s.insert(5);s.insert(5);s.insert(7);s.insert(2);for (auto e : s){cout << e << " ";     //2 5 6 7 10}cout << endl;//迭代器set<int>::iterator sit;pair<set<int>::iterator, bool> ret;   //接收插入返回值//pair<iterator, bool> insert(const value_type & val);        insert参数列表ret = s.insert(1);if (ret.second == true)sit = ret.first;cout << *sit << endl;    //1ret = s.insert(1);if (ret.second == false) sit = ret.first;cout << *sit << endl;    //1//iterator insert(iterator position, const value_type & val);  insert参数列表sit = s.insert(sit, 20);cout << *sit << endl;   //20//	template <class InputIterator>//void insert(InputIterator first, InputIterator last);        insert参数列表int arr[] = { 0,10,15 };            // 10 already in set, not inserteds.insert(arr, arr + 3);for (auto e : s){cout << e << " ";     //0 1 2 5 6 7 10 15 20}cout << endl;/////erase//void erase(iterator position);               erase参数列表s.erase(sit);    //*sit = 20//size_type erase(const value_type & val);     erase参数列表int e_ret = s.erase(0);cout << e_ret << endl;for (auto e : s){cout << e << " ";     //1 2 5 6 7 10 15}cout << endl;//void erase(iterator first, iterator last);   erase参数列表s.erase(s.begin(), s.end());for (auto e : s){cout << e << " ";     //empty}cout << endl;
}

(5)、iterator

void test_iteator()
{int arr[] = { 10,20,30,40,50 };set<int> s(arr, arr + 5);set<int>::iterator it = s.begin();set<int>::const_iterator cit = s.cbegin();set<int>::reverse_iterator rit = s.rbegin();set<int>::const_reverse_iterator crit = s.crbegin();while (it != s.end()){cout << *it << " ";   //10 20 30 40 50it++;}cout << endl;while (cit != s.cend()){cout << *cit << " ";   //10 20 30 40 50cit++;}cout << endl;while (rit != s.rend()){cout << *rit << " ";   //50 40 30 20 10rit++;}cout << endl;while (crit != s.crend()){cout << *crit << " ";  //50 40 30 20 10crit++;}cout << endl;
}

(6)、lower_bound和upper_bound

//iterator lower_bound(const value_type & val) const;                  lower_bound的声明
//iterator upper_bound(const value_type & val) const;                  upper_bound的声明
//pair<iterator, iterator> equal_range(const value_type& val) const;   equal_range的声明
void test_bound()
{set<int> s;set<int>::iterator itlow, itup;for (size_t i = 1; i < 10; i++){s.insert(i * 10);               //10 20 30 40 50 60 70 80 90}//左闭右开[30,70)itlow = s.lower_bound(30);itup = s.upper_bound(60);cout << *itlow << endl;        //30cout << *itup << endl;         //70set<int>::iterator it = s.lower_bound(35);//   s > 35cout << *it << endl;           //40//*it = 50;     //不能修改,保护键值s.erase(itlow, itup);for (auto e : s){cout << e << " ";             //10 20 70 80 90}cout << endl;////equal_range - most_use multiset//pair<set<int>::const_iterator, set<int>::const_iterator> auto ret1 = s.equal_range(15);itlow = ret1.first;itup = ret1.second;//因为不存在15,所以itlow和itup是一段不存在的区间cout << *itlow << endl;      //20   cout << *itup << endl;       //20   左开右闭auto ret2 = s.equal_range(80);itlow = ret2.first;itup = ret2.second;//[80,90)cout << *itlow << endl;     //80   cout << *itup << endl;      //90auto ret = s.equal_range(90);itlow = ret.first;itup = ret.second;//程序直接崩溃,到最后了cout << *itlow << endl;   //90     cout << *itup << endl;    //end()
}

2. multiset

这里的演示就不和set一样分开表示了,主要是multiset不去重

void test_multiset()
{//排序int arr[] = { 7, 7, 7, 3, 6, 5, 2, 3, 3, 3 };multiset<int> s(arr, arr + sizeof(arr) / sizeof(arr[0]));//不去重for (auto& e : s){cout << e << " ";}cout << endl;multiset<int>::iterator pos = s.find(3);  //返回中序遍历的第一个3while (pos != s.end())           //find失败返回end(){//*pos = 10;    //err  不能修改,保护键值cout << *pos << " ";++pos;}cout << endl;cout << s.count(3) << endl;   //4个3pair<multiset<int>::iterator, multiset<int>::iterator> ret = s.equal_range(7);multiset<int>::iterator itlow = ret.first;multiset<int>::iterator itup = ret.second;// [itlow, itup)// [7,end())  s.equal_range(7);//cout << *itlow << endl;//cout << *itup << endl;      //error   *itup没有值// [itlow, itup)// [5,5)  s.equal_range(4); ret = s.equal_range(4);itlow = ret.first;itup = ret.second;cout << *itlow << endl;cout << *itup << endl;       //oks.erase(itlow, itup);   //没有进行删除   [5, 5)for (auto e : s){cout << e << " ";}cout << endl;
}

3. map

(1)、模板参数列表

模板参数列表

(2)、构造

void test_constructor()
{map<string, string> dict;//"insert"和"插入"都分别有隐式类型转换,const char* 转成const string&//不能直接进行隐式类型转换,原因:多参数pair<string, string> kv1("insert", "插入");dict.insert(kv1);dict.insert(pair<string, string>("sort", "排序"));  //匿名对象//常用// C++98dict.insert(make_pair("string", "字符串"));// C++11 多参数的构造函数隐式类型转换dict.insert({ "string", "字符串" });   //{}会自动调用pair的构造// 隐式类型的转换  构造+拷贝构造(优化)string str1 = "hello";pair<string, string> kv2 = { "string", "字符串" };//const pair<string, string>& kv2 = { "string", "字符串" };  引用一个临时变量
}

(3)、modifiers和operations

void test_modifiers()
{map<string, string> dict;dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("insert", "插入"));dict.insert(make_pair("success", "成功"));//key已经有了就不会插入    //pair<iterator,bool> insert (const value_type& val);  插入的参数列表pair<map<string, string>::iterator, bool> ret = dict.insert(make_pair("insert", "xxx"));if (ret.second == false) {cout << "element already existed:";cout << ret.first->first << ":" << ret.first->second << endl;}//iterator insert (iterator position, const value_type& val);                      插入的参数列表map<string, string>::iterator it = dict.begin();it = dict.insert(it, make_pair("begin", "开始"));  // max efficiency insertingcout << it->first << ":" << it->second << endl;/*template <class InputIterator>void insert(InputIterator first, InputIterator last);*/                             //插入的参数列表map<string, string> copymap;//iterator find (const key_type& k); //查找的参数列表,返回值是查找这个位置的迭代器,如果没查找到,返回end()copymap.insert(dict.begin(), dict.find("success"));        it = dict.begin();while (it != dict.end()){//it->first = "xxx";   //error//it->second = "sss";  //ok//cout << (*it).first << ":" << (*it).second << endl;cout << it->first << ":" << it->second << endl;++it;}cout << endl;int number = dict.erase("sucess");cout << number << endl;for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}
}

(4)、operator[]

注意key不存在,operator[]是插入,at是抛异常

void test_operator()
{string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };map<string, int> countMap;for (const auto& e : arr){auto it = countMap.find(e);if (it == countMap.end()){countMap.insert(make_pair(e, 1));   //首次插入}else{it->second++;                       //统计次数}}//pair<map<char, int>::iterator, bool>::iterator it = this->insert(make_pair(k,mapped_type()))//(*(it.first)).secondfor (const auto& e : arr){//查找e是否存在,如果不存在进行插入,如果存在,返回valuecountMap[e]++;}for (const auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}
}

4. multimap

multimap和map的唯一不同,前者的key可以重复

二、封装

set和map的封装的底层结构使用的都是红黑树(这篇博客介绍了红黑树的旋转),在STL中set底层实际存储的数据是键值对< value, value >,这样就可以调用同个红黑树。

RBTree

迭代器原理

红黑树

双向迭代器 -> 根据红黑树的特征:

  1. 迭代器++,只需要判断当前位置的右侧节点的情况
  2. 迭代器- -,只需要判断当前位置的左侧节点的情况
  1. 迭代器++
  1. 右孩子不为空,访问右子树的最左节点(最小节点)。
  2. 右孩子为空,下一个访问的是孩子是父亲左的祖先节点。

代码实现:

Self& operator++()
{//右不为空if (_node->_right){//右子树的最左节点(右子树最小节点)Node* subLeft = _node->_right;while (subLeft->_left){subLeft = subLeft->_left;}_node = subLeft;}else  //右为空{Node* cur = _node;Node* parent = cur->_parent;//父节点为空,或者当前节点不是父节点的左孩子,循环继续while (parent && cur == parent->_right){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;
}
  1. 迭代器–
  1. 左孩子不为空,访问左子树的最右节点(最大节点)。
  2. 左孩子为空,下一个访问的是孩子是父亲右的祖先节点。
Self& operator--()
{//左孩子不为空if (_node->_left){Node* subRight = _node->_left;while (subRight->_right){subRight = subRight->_right;}_node = subRight;}else  //左孩子为空{ //孩子是父亲右的那个节点Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;
}

RBTree实现代码

//节点的颜色
enum Color
{RED,BLACK
};//这里一个模板参数T就可以,这个T既是set的key,也是map的value
template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Color _color;RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _color(RED){}
};//迭代器
template<class T, class Ptr, class Ref>
struct __TreeIterator
{typedef RBTreeNode<T> Node;typedef __TreeIterator<T, Ptr, Ref> Self;//无论被实例化成什么,都是普通迭代器typedef __TreeIterator<T, T*, T&> Iterator;//这个类被实列化成const迭代器时,这个函数是一个构造,支持普通迭代器构造const迭代器//这个类被实列化成普通迭代器时,这个函数是一个拷贝构造__TreeIterator(const Iterator& it):_node(it._node){}Node* _node;//节点初始化__TreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s){return _node != s._node;}Self& operator--(){if (_node->_left){Node* subRight = _node->_left;while (subRight->_right){subRight = subRight->_right;}_node = subRight;}else  { //孩子是父亲右的那个节点Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;}Self& operator++(){//右不为空if (_node->_right){//右子树的最左节点(右子树最小节点)Node* subLeft = _node->_right;while (subLeft->_left){subLeft = subLeft->_left;}_node = subLeft;}else  //右为空{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;}
};//set->RBTree<K, K, SetKeyOfT> _t;
//map->RBTree<K, pair<K, V>, MapKeyOfT> _t;//KeyOfT是上层传下来的仿函数
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef __TreeIterator<T, T*, T&> iterator;typedef __TreeIterator<T, const T*, const T&> const_iterator;iterator begin(){Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return iterator(leftMin);}iterator end(){//区分,这里和STL源码中的结束方式不同,return iterator(nullptr);}const_iterator begin() const{Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return iterator(leftMin);}const_iterator end() const{return iterator(nullptr);}//传K的作用Node* Find(const K& key){Node* cur = _root;KeyOfT kot;while (cur){if (kot(cur->_data) < key){cur = cur->_right;}else if (kot(cur->_data) > key){cur = cur->_left;}else{return cur;}}//没找到,返回nullptrreturn nullptr;}//注意insert的返回值是一个键值对pair<iterator, bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_color = BLACK;return make_pair(iterator(_root), true);}//寻找要链接新节点的位置Node* parent = nullptr;Node* cur = _root;KeyOfT kot;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}//插入节点 + 链接cur = new Node(data);cur->_color = RED;//保存节点,用于返回Node* newnode = cur;if (kot(parent->_data) > kot(data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;//调整   这里parent是否为空,是为了下一次循环判断//       如果parent->_color == BLACK也不用玩了while (parent && parent->_color == RED){Node* grandfather = parent->_parent;if (grandfather->_left == parent){Node* uncle = grandfather->_right;//u为红if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;grandfather->_color = RED;//继续向上调整cur = grandfather;parent = cur->_parent;}else //u不存在 或 存在且为黑{if (cur == parent->_left){//      g//   p//cRotateR(grandfather);parent->_color = BLACK;grandfather->_color = RED;}else{//      g//   p//      c	RotateL(parent);RotateR(grandfather);cur->_color = BLACK;grandfather->_color = RED;}//调整完之后,就不需要继续改变了break;}}else   //grandfather->_right == parent{Node* uncle = grandfather->_left;//u为红if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;grandfather->_color = RED;//继续向上调整cur = grandfather;parent = cur->_parent;}else //u不存在 或 存在且为黑{if (cur == parent->_right){//g//   p//      cRotateL(grandfather);parent->_color = BLACK;grandfather->_color = RED;}else{//g//   p//c	RotateR(parent);RotateL(grandfather);cur->_color = BLACK;grandfather->_color = RED;}//调整完之后,就不需要继续改变了break;}}}//根节点的颜色改成黑色_root->_color = BLACK;return make_pair(iterator(newnode), true);}//判断该树是不是红黑树bool IsBalance(){return _IsBalance(_root);}//计算红黑树的高度int Height(){return Height(_root);}private:int Height(Node* root){if (root == nullptr)return 0;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}bool CheckColor(Node* root, int blacknum, int benchmark){if (root == nullptr){if (blacknum != benchmark){return false;}return true;}//计算每条路径的黑色节点if (root->_color == BLACK){++blacknum;}if (root->_color == RED && root->_parent && root->_parent->_color == RED){cout << root->_kv.first << "出现连续红色节点" << endl;return false;}return CheckColor(root->_left, blacknum, benchmark)&& CheckColor(root->_right, blacknum, benchmark);}bool _IsBalance(Node* root){if (root == nullptr){return true;}if (root->_color != BLACK){return false;}//基准值 -->  用于比较别的路径黑色节点个数int benchmark = 0;Node* cur = _root;while (cur){if (cur->_color == BLACK)benchmark++;cur = cur->_left;}return CheckColor(root, 0, benchmark);}//旋转//都是二叉树的旋转,所以和AVLTree的旋转一样,只不过这里没有平衡因子void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright)curright->_parent = parent;Node* ppnode = parent->_parent;cur->_right = parent;parent->_parent = cur;if (ppnode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}}void RotateL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;//重新链接parent->_right = curleft;if (curleft)curleft->_parent = parent;cur->_left = parent;//提前保存parent->_parent,可能是根节点,也可能是子树的根节点Node* ppnode = parent->_parent;parent->_parent = cur;if (ppnode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}}private:Node* _root = nullptr;
};

map

namespace kpl
{template<class K, class V>class map{//RBTree仿函数的主要作用在这里,set的封装只是跟跑struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<const K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;};
}

set

namespace kpl
{template<class K>class set{//仿函数struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;//set只保留一个const即可const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}pair<iterator, bool> insert(const K& key){//这里返回值的first的迭代器是普通迭代器,用普通迭代器接收pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);//使用普通迭代器构造一个const的迭代器,这里就体现出迭代器实现中的那个拷贝构造return pair<iterator, bool>(ret.first, ret.second);}private:RBTree<K, K, SetKeyOfT> _t;};
}

三、总结

set

  1. 插入的元素只需要value,不用键值对
  2. set中的元素不能重复(set可以去重)
  3. 单个元素的访问速度比unordered_set慢
  4. 中序遍历有序,使用其迭代器访问也是有序
  5. 不允许修改,破坏结构

map

  1. map中的元素是键值对
  2. map中的key是唯一的,不能修改,但是value可以修改
  3. 中序遍历有序,使用其迭代器访问也是有序
  4. 支持operator[]
  5. 单个元素的访问速度比unordered_set慢

multiset和multimap(区分set和map)
multiset的value可以重复,multimap的key也可以重复

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

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

相关文章

9.输出国际象棋盘【2023.11.24】

1.问题描述 要求输出国际象棋棋盘。 2.解决思路 国际象棋棋盘由64个黑白相间的格子组成&#xff0c;分为8行*8列。用i控制行&#xff0c;j控制列&#xff0c;根据ij的和的变化来控制输出黑方格还是白方格。 3.代码实现 #include<stdio.h> int main(){for(int i0;i&…

基于广义正态分布算法优化概率神经网络PNN的分类预测 - 附代码

基于广义正态分布算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于广义正态分布算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于广义正态分布优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xf…

网络安全—自学

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

深度学习之基于Pytorch照片图像转漫画风格网络系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 以下是一个基本的设计介绍&#xff1a; 数据准备&#xff1a;收集足够的真实照片和漫画图像&#xff0c;用于训练模…

typora中的快捷键shift enter 和 enter的交换

1 问题&#xff1a; 我最近在用 typora 进行写作&#xff0c;但是在合格 typora 的 markdown 编辑器很奇怪&#xff0c;它的一个回车符是两次换行&#xff0c;而用 shfit ent 找了半天都不知道怎么解决的这个问题&#xff0c;然后我就去了这个 typora 在 github 开源的问题仓库…

hive 报错return code 40000 from org.apache.hadoop.hive.ql.exec.MoveTask解决思路

参考学习 https://github.com/apache/hive/blob/2b57dd27ad61e552f93817ac69313066af6562d9/ql/src/java/org/apache/hadoop/hive/ql/ErrorMsg.java#L47 为啥学习error code 开发过程中遇到以下错误&#xff0c;大家觉得应该怎么办&#xff1f;从哪方面入手呢&#xff1f; 1.百…

解决在Windows10或Windows11下无权限修改hosts文件

解决在Windows10或Windows11下无权限修改hosts文件&#xff0c;无法写入内容 1、首先在开始菜单中找到这个 2、接着输入&#xff1a; C:\Windows\System32\drivers\etc3、再次输入以下命令行&#xff1a;notepad hosts &#xff0c;并回车&#xff1a; notepad hosts 4、然后…

DataFunSummit:2023年现代数据栈技术峰会-核心PPT资料下载

一、峰会简介 现代数据栈&#xff08;Modern Data Stack&#xff09;是一种集合了多种技术和工具的软件基础设施&#xff0c;旨在更好地管理和处理数据&#xff0c;并为企业提供数据驱动的洞察和决策。包含以下几个组件&#xff1a;数据采集、数据处理、数据存储、数据查询和分…

区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第四套区块链应用后端开发

第四套区块链应用后端开发 环境 : ubuntu20 fisco : 2.8.0 springboot 2.1.1 fisco-java-sdk: 2.7.2 maven 3.8.8 前言 这套后端样题,只涉及调用fisco的系统接口,不涉及此食品溯源项目的业务接口,所以我就直接生成一个springboot项目进行完成此题目。 请提前准备好一…

Docker的项目资源参考

Docker的项目资源包括以下内容&#xff1a; Docker官方网站&#xff1a;https://www.docker.com/ Docker Hub&#xff1a;https://hub.docker.com/ Docker文档&#xff1a;https://docs.docker.com/ Docker GitHub仓库&#xff1a;https://github.com/docker Docker官方博客…

Unity中Shader的Standard材质解析(二)

文章目录 前言一、我们对 Standard 的 PBR 的 GI 进行解析1、我们先创建一个PBR的.cginc文件&#xff0c;用于整理用到的函数2、然后在Standard的Shader中引用该cginc文件 二、依次整理函数到该cginc文件中我们来看一下PBR中GI的镜面反射做了些什么 二、最终代码.cginc代码&…

【教学类-06-07】20231124 (55格版)X-X之间的加法、减法、加减混合题

背景需求 在大四班里&#xff0c;预测试55格“5以内、10以内、20以内的加法题、减法题、加减混合题”的“实用性”。 由于只打印一份20以内加法减法混合题。 “这套20以内的加减法最难”&#xff0c;我询问谁会做&#xff08;摸底幼儿的水平&#xff09; 有两位男孩举手想挑…

joplin笔记同步 到腾讯云S3

创建存储桶 打开腾讯云的存储桶列表&#xff0c;点击“创建存储桶”&#xff0c;输入名称&#xff0c;选择地域&#xff08;建议选择离自己较近的地域以降低访问时延&#xff09;和访问权限&#xff08;建议选择“私有读写”&#xff09;。 s3 存储桶&#xff1a; 存储桶的名称…

【经典小练习】简单的文件加密解密

文章目录 &#x1f339;什么是文件加密⭐应用场景 &#x1f6f8;案例&#x1f33a;描述&#x1f33a;代码 &#x1f339;什么是文件加密 Java文件加密是指使用Java编程语言和相关的加密算法对文件进行加密处理。通过这种方式&#xff0c;可以将文件内容转换为一种非常规的形式…

Halcon Solution Guide I basics(4): Blob Analysis(连通性解析)

文章目录 文章专栏前言文章解析开头步骤分析简单案例进阶方案 进阶代码案例crystal&#xff0c;结晶匹配需求分析 文章专栏 Halcon开发 Halcon学习 练习项目gitee仓库 CSDN Major 博主Halcon文章推荐 前言 今天来看第三章内容&#xff0c;既然是零基础&#xff0c;而且我还有大…

希宝猫罐头怎么样?专业人士告诉你口碑好的猫罐头推荐

作为一个从业宠物营养师7年的人&#xff0c;可以说对于猫咪的食物很有研究和猫罐头品牌选购上&#xff0c;我有自己的见解。那么希宝猫罐头怎么样呢&#xff1f; 希宝猫罐头采用了先进的加工工艺&#xff0c;注重产品的包装和密封性&#xff0c;其包装设计简洁时尚&#xff0c…

STM32 中断系统

单片机学习 目录 文章目录 前言 一、中断系统 1.1 什么是中断 1.2 中断优先级 1.3 中断嵌套 1.4 C语言中的中断程序 二、STM32的中断通道和中断向量 2.1 中断通道 2.2 嵌套向量中断控制器NVIC 2.2.1 什么是NVIC 2.2.2 NVIC基本结构 2.2.3抢占优先级和响应优先级 2.2.4 NVIC的优…

深度学习卷积神经网络参数计算难点重点

目录 一、卷积层图像输出尺寸 二、池化层图像输出尺寸 三、全连接层输出尺寸 四、卷积层参数数量 五、全连接层参数数量 六、代码实现与验证 以LeNet5经典模型为例子并且通道数为1 LeNet5网络有7层&#xff1a; ​ 1.第1层&#xff1a;卷积层 ​ 输入&#xff1a;原始的图片像素…

c语言数字转圈

数字转圈 题干输入整数 N&#xff08;1≤N≤9&#xff09;&#xff0c;输出如下 N 阶方阵。 若输入5显示如下方阵&#xff1a; * 1** 2** 3** 4** 5* *16**17**18**19** 6* *15**24**25**20** 7* *14**23**22**21** 8* *13**12**11**10** 9*输入样例3输出样例* 1*…

linux高级篇基础理论六(firewalld,防火墙类型,,区域,服务端口,富语言)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…