C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层

C++ 利用容器适配器,仿函数实现栈,队列,优先级队列【堆】,反向迭代器,deque的介绍与底层

  • 一.容器适配器的介绍
  • 二.利用容器适配器实现栈和队列
    • 1.stack
    • 2.queue
  • 三.仿函数介绍
    • 1.什么是仿函数
    • 2.仿函数的使用
    • 3.函数指针的使用
      • 1.函数指针的用处
      • 2.利用函数指针完成回调
      • 3.利用仿函数完成回调
    • 4.仿函数的玩法
      • 1.取出Key/Key-Value模型中的Key
      • 2.自定义排序
  • 四.利用容器适配器和仿函数实现优先级队列
  • 五.利用正向迭代器作为适配器实现反向迭代器
    • 1.STL库里面的实现逻辑
      • 1.rbegin和rend的实现
    • 2.反向迭代器的实现
    • 3.画图模拟反向迭代器具体的遍历流程
      • 1.vector
      • 2.list
    • 4.具体实现
    • 5.对于list的适用
    • 6.对于vector的适用
    • 7.const_reverse_iterator的实现
    • 8.验证
      • 1.list
      • 2.vector
  • 六.deque的介绍
  • 七.deque的底层原理

一.容器适配器的介绍

适配器是一种设计模式(所谓的设计模式就是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结,是很多大佬的编程的过程中总结下来的经验,类似于"武林秘籍"),
该种模式是将一个类的接口转换成客户希望的另外一个接口。

我们来看一下STL库中stack的源码,了解一下容器适配器模式到底是什么
在这里插入图片描述
下面就让我们借助容器适配器来实现一下栈和队列吧
实现之后大家就会对容器适配器模式有更加深刻的理解

二.利用容器适配器实现栈和队列

1.stack

#pragma once
//容器适配器:vector可以,list可以,deque也可以,库里面默认使用deque
namespace wzs
{template<class T, class Container = deque<T>>class stack{public://直接使用编译器默认生成的默认成员函数即可void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}T& top(){return _con.back();}const T& top()const{return _con.back();}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;};
}

可见,非常的easy
就是容器的复用而已
对于stack而言
它的适配器必须满足:
push_back,pop_back,back,size,empty这几个接口
因此stack的适配器可以是
vector
list
deque中的任何一个
在这里插入图片描述
验证完毕

2.queue

#pragma once
//容器适配器:list可以,deque也可以,库里面是deque,不过vector不可以,因为vector没有头删这个接口
namespace wzs
{template<class T, class Container = deque<T>>class queue{public://使用编译器默认生成的默认成员函数即可void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}T& back(){return _con.back();}const T& back()const{return _con.back();}T& front(){return _con.front();}const T& front()const{return _con.front();}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;};
}

可见,非常的easy
就是容器的复用而已
对于queue而言
它的适配器必须满足:
push_back,pop_front,back,front,size,empty这几个接口
因此stack的适配器可以是
list
deque中的任何一个
而vector因为没有pop_front这个接口,因此不能作为queue的适配器
在这里插入图片描述
验证完毕

三.仿函数介绍

1.什么是仿函数

仿函数,又叫做函数对象,它是一个类
只不过这个类重载了operator()这个运算符,使得这个类实例化出的对象在调用operator()这个函数时使用起来特别像一个函数,
也就是说这个类实例化出的对象能够像函数一样调用,因此这个类被称为仿函数

下面给大家演示一下
这是比较两个T类型的大小
在这里插入图片描述
只要一个类重载了operator(),这个类就是一个仿函数类
这个类实例化出的对象就能像函数一样进行调用

2.仿函数的使用

算法库里面的sort函数就使用了仿函数
在这里插入图片描述
默认情况下sort是排升序的
如果我们想要排降序呢?
就要用到仿函数了
我们来演示一下,顺便学习一下仿函数的语法和特性

默认排升序
在这里插入图片描述
排降序
在这里插入图片描述
sort的第三个参数要求传入仿函数对象,所以可以这样做
在这里插入图片描述
其实我们也可以自己实现一个仿函数
一般来说仿函数写出来就是为了给外界用的,所以定义成class的话要加public访问限定符调整成公有成员
不过也可以直接用struct定义这个类,毕竟struct定义的类的访问限定符默认就是public

template<class T>
struct greater
{bool operator()(const T& a, const T& b){return a > b;}
};

在这里插入图片描述
其实也可以直接传匿名对象,省下起名字了
在这里插入图片描述

3.函数指针的使用

1.函数指针的用处

可见仿函数是非常多功能的,那么它的用处是什么呢?
为什么C++创始人要设计仿函数这一语法呢?
仿函数是为了替代C语言当中的函数指针而出现的

我们知道函数指针是用来完成回调的,例如C语言库中的qsort函数
关于回调函数大家可以看我的这篇博客:征服C语言指针系列(3)
在这里插入图片描述
这里的比较规则就是由cmp这个函数指针来完成的

在学习堆的时候,我们曾经借助于函数指针来完成回调函数,实现无需修改具体函数的实现细节来完成大小堆的切换
数据结构-堆的实现及应用(堆排序和TOP-K问题)
在这里插入图片描述

2.利用函数指针完成回调

下面我们来演示一下使用函数指针完成回调

//返回a是否小于b
bool less1(int a, int b)
{return a < b;
}class A
{
public:A(bool (*p)(int,int)):_p(p){}//返回两个数中更小的那个数int smaller(int left, int right){if (_p(left, right)) return left;else return right;}private:bool (*_p)(int, int);
};int main()
{bool (*ptr)(int, int) = less1;A aa(ptr);cout << aa.smaller(1, 7) << endl;cout << aa.smaller(2, 5) << endl;return 0;
}

在这里插入图片描述
需要注意的是:

  1. 因为类A在回调less1这个函数时只能在类的成员函数进行
    而且可能类A的很多成员函数都需要回调less1这个函数,因此在类A当中增加了一个函数指针类型的成员变量,这个函数指针的参数类型和顺序以及返回值都需要跟less1这个函数一样

2.上面那个代码只能完成int和int的比较功能,无法完成string和string等等诸多类型的比较
并不符合泛型编程的思想

3.less1这个函数比较简单,因此这个函数指针并不复杂,可是那些很复杂的函数和类,如果使用函数指针的话…结果就让人很难受了

3.利用仿函数完成回调

下面我们来演示一下仿函数完成回调

template<class T>
class Less
{
public:bool operator()(const T& a, const T& b){return a < b;}
};template <class T,class Compare>
class A
{
public://返回两个元素中更小的那个元素const T& smaller(const T& left, const T& right){if (_cmp(left, right)) return left;else return right;}
private:Compare _cmp;
};int main()
{//注意:这里要往类模板的参数列表中传入实参//应该传入类型,而不是对象!!A<string, Less<string>> aa;cout << aa.smaller("abc", "wzs") << endl;A<int, Less<int>> ab;cout << ab.smaller(1, 8) << endl;return 0;
}

在这里插入图片描述
这样就既符合泛型编程的思想,使用起来也非常的好用了

4.仿函数的玩法

当然,仿函数的玩法是很多的,

1.取出Key/Key-Value模型中的Key

比如下面的这个例子:
这是取出一个键或者键值对当中的键
我们之前学过的二叉搜索树当中的Key模型和Key-Value模型就可以这样玩
这里是通过函数重载和类模板的缺省参数完成的
在这里插入图片描述

2.自定义排序

我们要实现一个比较算法,对不同的商品按照价格分别升序和降序排序

struct Goods
{string _name;//名称double _price;//价格int _evaluate;//评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};//按照价格升序
struct ComparePriceLess
{bool operator()(const Goods& left, const Goods& right){return left._price < right._price;}
};//按照价格降序
struct ComparePriceGreater
{bool operator()(const Goods& left, const Goods& right){return left._price > right._price;}
};int main()
{vector<Goods> v = { { "苹果", 2.5, 5 }, { "香蕉", 3.2, 4 }, { "橙子", 2.9, 3 }, { "菠萝", 1.5, 4 } };sort(v.begin(),v.end(), ComparePriceLess());for (auto& e : v){cout << "商品名称: " << e._name << " 价格 :" << e._price << " 评价:" << e._evaluate << endl;}cout << endl;sort(v.begin(), v.end(), ComparePriceGreater());for (auto& e : v){cout << "商品名称: " << e._name << " 价格 :" << e._price << " 评价:" << e._evaluate << endl;}cout << endl;return 0;
}

在这里插入图片描述
这样就可以按照我们想要的方式自定义排序规则进行排序了
当然,仿函数也有一个缺点:使用仿函数完成回调必须要定义出一个类来,有点大材小用的感觉
因此我们以后会介绍一个C++11新增的语法:lambda表达式,它可以在这种情况下替代仿函数

四.利用容器适配器和仿函数实现优先级队列

优先级队列其实就是堆,
关于堆的知识,实现,应用,大家可以看我的这篇博客,里面有详细的介绍:数据结构-堆的实现及应用(堆排序和TOP-K问题)
头文件是<queue>
在这里插入图片描述
它也可以用容器适配器来实现
默认是大堆,要想实现小堆的话:第三个参数仿函数传入greater类

容器适配器:vector可以,deque也可以,库里面是vector
因为要能够支持下标随机访问(也就是operator[]),而且vector的operator[]的速度远高于deque

#pragma once
//priority_queue的头文件是queue
//priority_queue默认是大堆
//要想实现小堆的话:第三个参数仿函数传入greator类
//容器适配器:vector可以,deque也可以,库里面是vector
//大堆:父亲大于孩子
//小堆:父亲小于孩子
namespace wzs
{template <class T, class Container = vector<T>, class Compare = less<T> >class priority_queue{public://使用编译器默认生成的默认成员函数即可priority_queue() = default;//C++11新语法:强制生成默认构造template <class InputIterator>//迭代器区间构造priority_queue(InputIterator first, InputIterator last):_con(first, last){//先调一下迭代器区间构造,构造适配器对象_con//然后建堆即可//注意:向上调整算法建堆的时间复杂度O(N*logN)//向下调整算法建堆的时间复杂度O(N)//因此这里向下建堆for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){adjust_down(i);}}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}const T& top() const{return _con.front();}T& top(){return _con.front();}//向上调整算法void adjust_up(int child){int parent = (child - 1) / 2;while (child > 0){if (_cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){//先插入数据,然后向上调整_con.push_back(x);adjust_up(_con.size() - 1);}//向下调整算法void adjust_down(int parent){int child = 2 * parent + 1;//默认跟左孩子比较int n = _con.size();while (child < n){//实际要跟右孩子比较if (child + 1 < n && _cmp(_con[child], _con[child + 1])){child++;}if (_cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = 2 * parent + 1;}else{break;}}}void pop(){//先交换第一个和最后一个数据swap(_con[0], _con[_con.size() - 1]);//然后删除最后一个数据_con.pop_back();//最后向下调整adjust_down(0);}private:Container _con;Compare _cmp;};//仿函数greatertemplate<class T>struct greater{bool operator()(const T& a, const T& b){return a > b;}};
};

注意:
建小堆传入仿函数时:
因为优先级队列的类模板中规定仿函数传入类
因此不能传入对象,而且缺省参数也不支持跳着传

priority_queue<int, greater<int>> heap;//err:仿函数是第三个参数,只有在第二个参数传了之后才能传第3个参数
priority_queue<int,vector<int>, greater<int>()> heap;//err:仿函数是类模板,必须传入类型,不能传入对象
priority_queue<int, vector<int>, greater<int>> heap;//yes,正确的传法

在这里插入图片描述

五.利用正向迭代器作为适配器实现反向迭代器

下面我们来通过适配器的知识借助vector和list的正向迭代器实现它们的反向迭代器

首先要说明的是,反向迭代器是这么使用的
会反向打印这个容器中的数据
这里以vector为例,对于其他支持迭代器的容器来说也是这样的
在这里插入图片描述

1.STL库里面的实现逻辑

1.rbegin和rend的实现

在这里插入图片描述

2.反向迭代器的实现

在这里插入图片描述

3.画图模拟反向迭代器具体的遍历流程

1.vector

在这里插入图片描述

2.list

在这里插入图片描述
可见STL大佬的实现体现出了一种对称美(rbegin就是end,rend就是begin)
下面我们就来实现一下

4.具体实现

// 适配器 -- 复用
template<class Iterator, class Ref, class Ptr>
struct Reverse_iterator
{typedef Reverse_iterator<Iterator, Ref, Ptr> Self;//构造函数Reverse_iterator(Iterator it):_it(it){}Iterator _it;Ref operator*(){Iterator tmp(_it);return *(--tmp);}Ptr operator->(){return &(operator*());}//前置++Self& operator++(){--_it;return *this;}//前置--Self& operator--(){++_it;return *this;}//后置++Self& operator++(int){Self tmp(*this);--_it;return tmp;}//后置--Self& operator--(int){Self tmp(*this);++_it;return tmp;}bool operator==(const Self& s){return _it == s._it;}bool operator!=(const Self& s){return _it != s._it;}
};

5.对于list的适用

template<class T>
class list
{typedef list_node<T> Node;
public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}//其他成员....无需改动
}

6.对于vector的适用

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;/// 迭代器相关iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}其他成员.... 无需改动

7.const_reverse_iterator的实现

关于const_reverse_iterator的实现,我们需要实现支持使用普通的reverse_iterator来构造const_reverse_iterator
因此我们需要增加一个模板参数T

template<class T,class Iterator,class Ref,class Ptr>
struct Reverse_iterator
{typedef Reverse_iterator<T, Iterator, Ref, Ptr> Self;typedef Reverse_iterator<T, Iterator, T&, T*> reverse_iterator;Iterator cur;Reverse_iterator(Iterator it):cur(it){}//支持reverse_iterator向const_reverse_iterator的构造Reverse_iterator(const reverse_iterator& it):cur(it.cur){}//运算符重载都是一样的
};

因为const迭代器中const保护迭代器指向的内容不被修改的功能是由解引用操作的返回值类型即Ref和Ptr所决定的,
因此可以在list和vector当中这么定义const_reverse_iterator
这份代码在list和vector当中都是一样的

typedef Reverse_iterator<T, iterator,const T&,const T*> const_reverse_iterator;const_reverse_iterator rbegin() const
{return const_reverse_iterator(end());
}const_reverse_iterator rend() const
{return const_reverse_iterator(begin());
}

8.验证

1.list

class AA
{
public:AA(int a = 1,int b = 2):_a(a),_b(b){}int _a;int _b;
};void TestReverseIterator()
{list<int> lt;int a[] = { 1,2,3,4,5,6,7,8,9,10 };for (auto& e : a){lt.push_back(e);}list<int>::reverse_iterator it = lt.rbegin();while (it != lt.rend()){*it -= 5;//可以修改cout << *it << " ";++it;}cout<<endl;list<AA> lt2;for (auto& e : a){lt2.push_back(AA(e,e));}list<AA>::const_reverse_iterator it2 = lt2.rbegin();while (it2 != lt2.rend()){//it2->_b -= 2;//不可修改cout << it2->_a << ":" << it2->_b << endl;++it2;}}

在这里插入图片描述
验证成功

2.vector

void TestReverseIterator2()
{vector<int> v;int a[] = { 1,2,3,4,5,6,7,8,9,10 };for (auto& e : a){v.push_back(e);}vector<int>::reverse_iterator it = v.rbegin();while (it != v.rend()){*it -= 5;//可以修改cout << *it << " ";++it;}cout<<endl;vector<AA> v2;for (auto& e : a){v2.push_back(AA(e,e));}vector<AA>::const_reverse_iterator it2 = v2.rbegin();while (it2 != v2.rend()){//it2->_b -= 2;//不可修改cout << it2->_a << ":" << it2->_b << endl;++it2;}
}

在这里插入图片描述
验证成功

六.deque的介绍

deque:双端队列,名字叫做双端队列,但是跟队列没有任何关系
在这里插入图片描述

七.deque的底层原理

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的
deque的底层是一个指针数组
deque为了维护其“整体连续”以及随机访问的假象,所以它的迭代器就比较复杂了
在这里插入图片描述
在这里插入图片描述

通过保证每一个tmp数组的大小都是一样的,这样就能实现O(1)的operator[]了,

假设每个tmp数组的大小都是n,要查找下标为pos的元素 那么就是第pos/n个tmp数组的第pos%n个元素

对于deque来说我们了解即可,因为deque无法取代vector和list
实际并不常用

以上就是C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层的全部内容,希望能对大家有所帮助!

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

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

相关文章

免 费 小程序商城搭建之b2b2c o2o 多商家入驻商城 直播带货商城 电子商务b2b2c o2o 多商家入驻商城 直播带货商城 电子商务

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

cg插画设计行业怎么样,如何学习插画设计

插画设计行业是一个充满创意和艺术性的行业&#xff0c;随着数字化时代的不断发展&#xff0c;cg插画的应用范围越来越广泛&#xff0c;市场需求也在逐年增长。以下是一些关于acg插画设计行业的现状和发展趋势&#xff1a; 市场需求不断增长&#xff1a;随着广告、媒体、影视、…

HCIA学习作业二

要求&#xff1a;基于192.168.1.0/24进行合理划分&#xff0c;要求全网通 [AR3]display ip interface brief [AR3]display ip routing-table [AR1]display ip interface brief [AR1]display ip routing-table [AR2]display ip interface brief [AR2]display ip routing-tab…

Hadoop3.x源码解析

文章目录 一、RPC通信原理解析1、概要2、代码demo 二、NameNode启动源码解析1、概述2、启动9870端口服务3、加载镜像文件和编辑日志4、初始化NN的RPC服务端5、NN启动资源检查6、NN对心跳超时判断7、安全模式 三、DataNode启动源码解析1、概述2、初始化DataXceiverServer3、初始…

《WebKit 技术内幕》学习之十一(2):多媒体

2 视频 2.1 HTML5视频 在HTML5规范定义中&#xff0c;Web开发者可以使用“video”元素来播放视频资源。视频中有个重要的问题就是视频编码格式&#xff0c;对此&#xff0c;目前标准中包含了三种编码格式&#xff0c;它们分别是Ogg、MPEG4和WebM。其中Ogg是由Xiph.org组织开…

【模拟算法系列】详解5道题

本文讲解模拟算法系列的5道经典题&#xff0c;在讲解题目的同时提供AC代码&#xff0c;点击题目即可打开对应OJ链接 目录 模拟算法的介绍 1、替换所有的问号 2、提莫攻击 3、 Z 字形变换 4、外观数列 5、数青蛙 模拟算法的介绍 题目中明确告诉你要干什么&#xff0c;思路…

ChatGPT 和文心一言 | 两大AI助手哪个更胜一筹

欢迎来到英杰社区&#xff1a; https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区&#xff1a; https://bbs.csdn.net/topics/617897397 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff…

Web开发4:单元测试

在Web开发中&#xff0c;单元测试是一种重要的开发实践&#xff0c;它可以帮助我们确保代码的质量和可靠性。通过编写和运行单元测试&#xff0c;我们可以验证代码的正确性&#xff0c;减少错误和缺陷&#xff0c;并提高代码的可维护性。本文将介绍单元测试的概念、好处以及如何…

python写一个彩票中奖小游戏修订版本

先说规则&#xff1a; print("下面介绍双色球颜色规则:")print("一等奖,投注号码与当期开奖号码全部相同&#xff08;顺序不限&#xff0c;下同&#xff09;&#xff0c;即中奖")print("二等奖:投注号码与当期开奖号码中的6个红色球号码相同,即中奖&q…

鸿蒙开发实战-手写文心一言AI对话APP

运行环境 &#xff08;后面附有API9版本&#xff0c;可修改后在HarmonyOS4设备上运行&#xff09; DAYU200:4.0.10.16 SDK&#xff1a;4.0.10.15 IDE&#xff1a;4.0.600 在DAYU200:4.0.10.16上运行 一、创建应用 1.点击File->new File->Create Progect 2.选择模版…

分享7种SQL的进阶用法

分享7种SQL的进阶用法 前言 还只会使用SQL进行简单的insert、update、detele吗&#xff1f;本文给大家带来7种SQL的进阶用法&#xff0c;让大家在平常工作中使用SQL简化复杂的代码逻辑。 1.自定义排序&#xff08;ORDER BY FIELD&#xff09; 在MySQL中ORDER BY排序除了可以…

temu跨境电商怎么样?做temu蓝海项目有哪些优势?

在全球电商市场激烈的竞争中&#xff0c;Temu跨境电商平台以其独特的优势和策略&#xff0c;逐渐崭露头角。对于许多想要拓展海外市场的商家来说&#xff0c;Temu的蓝海项目提供了一个充满机遇的新平台。本文将深入探讨Temu跨境电商的优势以及在蓝海市场中的发展前景。 全球化市…

编程笔记 html5cssjs 056 CSS不透明度

编程笔记 html5&css&js 056 CSS不透明度 一、CSS 不透明度 / 透明度二、使用 RGBA 的透明度三、透明盒中的文本小结 不透明度/透明度。利用透明度可以提高页面的层次效果。 一、CSS 不透明度 / 透明度 opacity 属性指定元素的不透明度/透明度。 opacity 属性通常与 :h…

仅使用 Python 创建的 Web 应用程序(前端版本)第08章_商品详细

在本章中,我们将实现一个产品详细信息页面。 完成后的图像如下。 Model、MockDB、Service都是在产品列表页实现的,所以创建步骤如下。 No分类内容1Page定义PageId并创建继承自BasePage的页面类2Application将页面 ID 和页面类对添加到 MultiPageApp 的页面中Page:定义PageI…

VsCode提高生产力的插件推荐-持续更新中

别名路径跳转 自定义配置// 文件名别名跳转 "alias-skip.mappings": { "~/": "/src", "views": "/src/views", "assets": "/src/assets", "network": "/src/network", "comm…

Android App开发基础(2)—— App的工程结构

本专栏文章 上一篇 Android开发修炼之路——&#xff08;一&#xff09;Android App开发基础-1 2 App的工程结构 本节介绍App工程的基本结构及其常用配置&#xff0c;首先描述项目和模块的区别&#xff0c;以及工程内部各目录与配置文件的用途说明&#xff1b;其次阐述两种级别…

THM学习笔记——OSI模型和TCP/IP模型

全是文字 比较枯燥 建议视频 OSI模型由七个层次组成&#xff1a; 第7层 -- 应用层&#xff1a; OSI模型的应用层主要为在计算机上运行的程序提供网络选项。它几乎专门与应用程序一起工作&#xff0c;为它们提供一个界面以用于传输数据。当数据传递到应用层时&#xff0c;它…

【医学图像隐私保护】联邦学习:密码学 + 机器学习 + 分布式 实现隐私计算,破解医学界数据孤岛的长期难题

联邦学习&#xff1a;密码学 机器学习 分布式 提出背景&#xff1a;数据不出本地&#xff0c;又能合力干大事联邦学习的问题 分布式机器学习&#xff1a;解决大数据量处理的问题横向联邦学习&#xff1a;解决跨多个数据源学习的问题纵向联邦学习&#xff1a;解决数据分散在多…

【grafana】使用教程

【grafana】使用教程 一、简介二、下载及安装及配置三、基本概念3.1 数据源&#xff08;Data Source&#xff09;3.2 仪表盘&#xff08;Dashboard&#xff09;3.3 Panel&#xff08;面板&#xff09;3.4 ROW&#xff08;行&#xff09;3.5 共享及自定义 四、常用可视化示例4.1…

湿法蚀刻酸洗槽—— 应用半导体新能源光伏光电行业

PFA清洗槽又被称为防腐蚀槽、酸洗槽、溢流槽、纯水槽、浸泡槽、水箱、滴流槽&#xff0c;是四氟清洗桶后的升级款&#xff0c;是为半导体光伏光电等行业设计&#xff0c;一体成型&#xff0c;无需担心漏液。主要用于浸泡、清洗带芯片硅片电池片的花篮。 由于PFA的特点它能耐受…