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.hqwc.cn/news/215106.html

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

相关文章

python——第十三天

uuid 是通用唯一识别码&#xff08;Universally Unique identifier&#xff09;的缩写 UUID是一个128比特的数值 uuid模块&#xff1a; 获取一个128位&#xff08;比特&#xff09;的永不重复的数字&#xff0c;当然我们使用的时候会转换为32个的字符串 impor uuud uui…

React + BraftEditor 实现富文本编辑

Braft Editor 是一个基于 React 和 Draft-js 开发的富文本编辑器&#xff0c;提供了丰富的基础功能&#xff0c;如基本文本格式化、列表、链接、图片上传、视频插入等&#xff0c;并且还支持扩展。 首先&#xff0c;确保你已经在项目中安装了 Braft Editor 和它的依赖项&#x…

免费时代结束:百度云加速取消所有免费套餐

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 在网站时代&#xff0c;凭借着“品牌”“SEO”“免费”的优势&#xff0c;百度云加速一跃成为国内最大的CDN服务商。但随着站长时代结束&#xff0c;和网站相关的产品越来越少&#xff0c;收费的名…

Langchain的Agents介绍

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

卷积神经网络(CNN)识别验证码

文章目录 一、前言二、前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据3. 查看数据4.标签数字化 二、构建一个tf.data.Dataset1.预处理函数2.加载数据3.配置数据 三、搭建网络模型四、编译五、训练六、模型评估七、保存和加载模型八、预测 …

产品经理必备技能:竞品分析!秒懂竞品分析,写竞品分析报告看这篇就够了!

在这个竞争激烈的时代&#xff0c;每一个想要成功的企业不可避免地要进行竞品分析。竞品分析就像是一把锐利的剑&#xff0c;可以帮助我们洞察市场&#xff0c;了解对手&#xff0c;找出自己的优势和弱点。 但这并不是一件容易的事情&#xff0c;需要我们投入大量的时间和精力…

Fiddler 无法抓包手机 https 报文的解决方案来啦!!

解决手机https无法抓包的问题 当你测试App的时候&#xff0c;想要通过Fiddler/Charles等工具抓包看下https请求的数据情况&#xff0c;发现大部分的App都提示网络异常/无数据等等信息 这时候怎么解决呢&#xff1f; 以软件测试面试提刷题APP为例&#xff1a; Fiddler上的显示…

YOLOv5 第Y6周 模型改进

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营 &#x1f356; 原作者&#xff1a;[K同学啊] &#x1f680; 文章来源&#xff1a;[K同学的学习圈子](https://www.yuque.com/mingtian-fkmxf/zxwb4…

Python之Pygame游戏编程详解

一、介绍 1.1 定义 Pygame是一种流行的Python游戏开发库&#xff0c;它提供了许多功能&#xff0c;使开发人员可以轻松创建2D游戏。它具有良好的跨平台支持&#xff0c;可以在多个操作系统上运行&#xff0c;例如Windows&#xff0c;MacOS和Linux。在本文中&#xff0c;我们将…

基于java技术的社区交易二手平台

基于java技术的社区交易二手平台的设计与实现 &#xff08;一&#xff09;开发背景 随着因特网的日益普及与发展&#xff0c;更多的人们开始通过因特网来寻求便利。但是&#xff0c;许多人都觉得网上商店里的东西不贵。所以&#xff0c;有些顾客宁愿去那些用二次定价建立起来的…

全球服的游戏服务器架构设计

全球服的游戏服务器架构设计 版权声明 本文为“优梦创客”原创文章&#xff0c;您可以自由转载&#xff0c;但必须加入完整的版权声明 文章内容不得删减、修改、演绎 相关学习资料见文末 主题 常见服务器端架构划分 不同类型游戏的架构选择与瓶颈 如何设计通用、可伸缩的…

BGP联邦及路由反射器配置

需求 1 AS1存在两个环回&#xff0c;一个地址为192.168.1.0/24&#xff0c;该地址不能再任何协议中宣告 AS3存在两个环回&#xff0c;一个地址为192.168.2.0/24&#xff0c;该地址不能再任何协议中宣告 AS1还有一个环回地址为10.1.1.0/24&#xff0c;AS3另一个环回地址是11.1.1…