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;
}
需要注意的是:
- 因为类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的介绍与底层的全部内容,希望能对大家有所帮助!
相关文章:
C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层
C 利用容器适配器,仿函数实现栈,队列,优先级队列【堆】,反向迭代器,deque的介绍与底层 一.容器适配器的介绍二.利用容器适配器实现栈和队列1.stack2.queue 三.仿函数介绍1.什么是仿函数2.仿函数的使用3.函数指针的使用1.函数指针的用处2.利用函数指针完成回调3.利用仿函数完成回…...
C语言实战系列二:简单超市收银系统
从一个简单的超市收银系统,我们来练习一个系统如何设计,然后如何实现的思路。 在Ubuntu环境下使用C语言编写一个简单的超市收银系统。以下是一个基本的示例,涵盖了商品管理、购物车、交易处理等功能。 代码 #include <stdio.h> #inc…...
coding推送代码Jenkins自动构建部署
实现功能:我们向coding推送代码,通过webhook自动通知Jenkins,实现自动构建部署 coding 项目设置 / 开发者选项 / Service Hook 输入以下参数 发送POST请求服务 URL:htttp://xxx用户名:xxx密码:xxx Jen…...
Kettle-Docker部署+Sqlserver数据同步Mysql+Start定时任务
一. 背景介绍 1. ETL是什么 ETL(Extract-Transform-Load),即数据抽取、转换、装载的过程。它是一种思想,主要是说,从不同的数据源获取数据,并通过对数据进行处理(格式,协议等转换&a…...
《微信小程序开发从入门到实战》学习九十三
7.1 视图容器组件 7.1.3 swiper与swiper-item组件 swiper组件的显示效果如下图所示: indicator-dots、indicator-color和indicator-active-color三个属性用于设置swiper组件下方的指示点。设置指示点的颜色时,可以使用HexColor,也可以使用r…...
Java服务端使用freemarker+wkhtmltoimage生成Echart图片
目录 1.通过 freemarker 将ftl转成html 1.1 freemarker 手册: 1.2 添加freemarker maven依赖 1.3 添加 echart-test.ftl 模版文件 1.4 添加 FreemarkerTool 工具类 1.5 添加测试main方法 1.6 运行,生成echart-test-时间戳.html 文件 2. 通过wkhtmltoimage将html 转为p…...
一款颜值与实力并存的翻页时钟(免费)
FliTik是一款颜值与实力并存的翻页时钟,安卓端是完全免费的,无任何广告,极简风 ,软件默认是12小时制,可以在设置中启用24小时制,并且还支持设置显示秒钟、日期、文案,滴答声和语音报时。 支持横…...
Objective-C方法的声明实现及调用
1.无参数的方法 1)声明 a.位置:在interface括弧的外面 b.语法: - (返回值类型)方法名称; interface Person : NSObject -(void) run; end 2)实现 a.位置:在implementation中实现 b.语法:加大括弧将方法实现的代码写在大括孤之中 …...
第十四届蓝桥杯国赛 C++ B 组 C 题——班级活动(AC)
目录 1. 班级活动1. 问题描述2. 输入格式3. 输出格式4. 样例输入5. 样例输出6. 样例说明7. 评测用例规模与约定8. 原题链接 2. 解题思路3. AC_Code 1. 班级活动 前置知识点:思维,分类讨论 1. 问题描述 小明的老师准备组织一次班级活动。班上一共有 n…...
GraphQL的力量:简化复杂数据查询
1. GraphQL GraphQL 是一种由 Facebook 开发并于 2015 年公开发布的数据查询和操作语言,也是运行在服务端的运行时(runtime)用于处理 API 查询的一种规范。不同于传统的 REST API,GraphQL 允许客户端明确指定它们需要哪些数据&am…...
python环境安装sklearn及报错解决
安装 如刚开始安装,还未遇到问题请直接从重新安装库开始看,如果遇到报错,从问题开始看 问题 python安装sklearn报错 ,报错信息如下 File "<stdin>", line 1pip install scikit-learn^ SyntaxError: invalid s…...
log4j:WARN Please initialize the log4j system properly的解决办法
背景:很多次创建新项目log4j都出现以下2个警告: log4j:WARN No appenders could be found for logger (org.springframework.boot.ApplicationServletEnvironment).log4j:WARN Please initialize the log4j system properly 网上查询都是在说缺少以下jar…...
虹科分享丨汽车技术的未来:Netropy如何测试和确保汽车以太网的性能
来源:艾特保IT 虹科分享丨汽车技术的未来:Netropy如何测试和确保汽车以太网的性能 原文链接:https://mp.weixin.qq.com/s/G8wihrzqpJJOx5i0o63fkA 欢迎关注虹科,为您提供最新资讯! #汽车以太网 #车载网络 #Netropy …...
代码CE:reference to ‘XX‘ is ambiguous
代码CE:reference to ‘XX’ is ambiguous 今天提交代码的时候一直错误,CE,搞不明白明明在dev上成功,为什么提交失败。 现在懂了,因为定义的变量和C内部函数或变量重名了。修改之后即可AC。 int data[21][21]{0}; int maxsum[21…...
如果想将企业微信的组织架构同步到内部知识库咋搞?方法来也!
在现代企业的运营中,内部知识库不仅储存了公司的宝贵知识资产,还充当着员工信息共享和协作的核心平台。为了保障知识库的效能最大化,使其成为支持决策、创新和培训的强大工具,企业必须拥有一套周到的权限管理机制。对此࿰…...
【c语言】扫雷
前言: 扫雷是一款经典的单人益智游戏,它的目标是在一个方格矩阵中找出所有的地雷,而不触碰到任何一颗地雷。在计算机编程领域,扫雷也是一个非常受欢迎的项目,因为它涉及到许多重要的编程概念,如数组、循环…...
自然语言处理的崛起:从初步分析到深度理解
自然语言处理(NLP)是计算机科学、人工智能和语言学的交叉领域,旨在让计算机能够理解和生成人类语言。随着时间的推移,NLP 经历了一系列革命性的变化,从简单的规则和模式匹配到如今的深度学习模型,它们使计算…...
Git学习笔记:版本回滚
文章目录 回到过去:开启新时间线,时间分叉路口1. 回溯开发2. 临时恢复特性3. 实验性开发4. 分支维护和发布5. 调试历史问题类比推理: 方法:1. 临时查看旧版本2. 永久回滚到旧版本3. 创建新的分支指向旧版本 回到过去:开…...
OpenCV图像的基本操作
图像的基本操作(Python) 素材图 P1:die.jpg P2:cool.jpg V:rabbit.mp4, 下载地址 读取展示-图像 import cv2img_1 cv2.imread(./die.jpg) # default cv2.IMREAD_COLOR print("die.jpg shape(imre…...
小白水平理解面试经典题目LeetCode 594 Longest Harmonious Subsequence(最大和谐字符串)
594 最大和谐字符串 这道题属于字符串类型题目,解决的办法还是有很多的,暴力算法,二分法,双指针等等。 题目描述 和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。 现在,给你一个整数数组 nums …...
Vue-35、Vue中使用ref属性
1、ref属性 2、代码 <template><div id"app"> <!-- <img alt"Vue logo" src"./assets/logo.png">--><h1 v-text"msg" ref"title"></h1><button click"showDOM" ref&…...
网络通信(15)-C#TCP客户端掉线重连实例
本文上接前面的文章使用Socket在C#语言环境下完成TCP客户端的掉线重连实例。 掉线重连需要使用心跳包发送测试网络的状态,进而进入重连循环线程。 前面实例完成的功能: 客户端与服务器连接,实现实时刷新状态。 客户端接收服务器的数据。 客户端发送给服务器的数据。 客…...
React进阶 - 14(说一说”虚拟DOM“中的”Diff算法“)
本章内容 目录 一、了解 Diff 算法二、key 值的重要性三、为什么不建议使用 index 做 key 值 上一节我们初步了解了 React中的”虚拟 DOM“ ,本节我们来说一说”虚拟DOM“中的”Diff算法“ 一、了解 Diff 算法 在上一篇中,我们有讲到:当 st…...
#GPU|LLM|AIGC#集成显卡与独立显卡|显卡在深度学习中的选择与LLM GPU推荐
区别 核心区别:显存,也被称作帧缓存。独立显卡拥有独立显存,而集成显卡通常是没有的,需要占用部分主内存来达到缓存的目的 集成显卡: 是集成在主板上的,与主处理器共享系统内存。 一般会在很多轻便薄型的…...
HCIP-IPV6实验
实验拓扑 实验需求 全网可达 实验思路 配置IP地址 配置路由协议-ospf 配置R2 配置IPV6 配置R2Tunnel 将所有地址引流到Tunnel0/0/0接口 ripng配置 汇总 实验步骤 配置IP地址 以R2为例 [Huawei]sys r2 [r2]int g0/0/0 [r2-GigabitEthernet0/0/0]ip address 12.1.1…...
如何训练和导出模型
介绍如何通过DI-engine使用DQN算法训练强化学习模型 一、什么是DQN算法 DQN算法,全称为Deep Q-Network算法,是一种结合了Q学习(一种价值基础的强化学习算法)和深度学习的算法。该算法是由DeepMind团队在2013年提出的,…...
Springboot注解@Aspect(一)之@Aspect 作用和Aop关系详解
目录 Aspect的使用 配置 作用 通知相关的注解 例子 结果: Aspect作用和Spring Aop关系 示例 标签表达式 Aspect的使用 配置 要启用 Spring AOP 和 Aspect 注解,需要在 Spring 配置中启用 AspectJ 自动代理,但是在 Spring Boot 中&a…...
自动化防DDoS脚本
简介 DDoS (分布式拒绝服务攻击)是一种恶意的网络攻击,旨在通过占用目标系统的资源,使其无法提供正常的服务。在DDoS攻击中,攻击者通常控制大量的被感染的计算机或其他网络设备,同时将它们协调起来向目标系…...
ubuntu怎么查看有几个用户
在Ubuntu中,可以使用以下命令来查看系统中的用户数量: cat /etc/passwd | wc -l这个命令会读取 /etc/passwd 文件中的用户信息,并使用 wc -l 命令来计算行数,即用户数量。 另外,你也可以使用以下命令来查看当前登录到…...
Linux | makefile简单教程 | Makefile的工作原理
前言 在学习完了Linux的基本操作之后,我们知道在linux中编写代码,编译代码都是要手动gcc命令,来执行这串代码的。 但是我们难道在以后运行代码的时候,难道都要自己敲gcc命令嘛?这是不是有点太烦了? 在vs中…...
织梦网站怎么做备份/自己建网站怎样建
车牌识别行业已具备一定的市场规模,在电子警察、公路卡口、停车场、商业管理、汽修服务等领域已取得了部分应用。 import glob # Contains all .txt files except our listof classes txt_files [file for file inglob.glob(images/*.txt) if file ! images/clas…...
php框架做网站好处/环球贸易网
L1-003 个位数统计 (15 分) 给定一个 k 位整数 Ndk−110k−1⋯d1101d0 (0≤di≤9, i0,⋯,k−1, dk−1>0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N100311,则有 2 个 0,3 个 1,和 1 个…...
做soho外贸网站/怎样自己做网站
在介绍KDE和Gnome之前,我们有必要先来介绍UNIX/Linux图形环境的概念。对一个习惯Windows的用户来说,要正确理解UNIX/Linux的图形环境可能颇为困难,因为它与纯图形化Windows并没有多少共同点。Linux实际上是以UNIX为模板的,它继承了…...
网站模板站的模板展示怎么做的/网站优化与seo
方法一:伪列布局法(利用背景图)所谓伪列布局法,就是设计一个背景图像,利用背景图像来模拟栏目的背景。如,使用Photoshop设计一个长方形的背景图,长度与页面宽度保持一致,高度任意。代码中要用到的背景图&am…...
web开发是网站开发吗/关键词排名优化方法
遇到问题: 第一次从外部文件导入Blog_bug工程到Workspace目录中,成功。 删除后,再次从外部导入Workspace目录提示 Some projects cannot be imported because they already exist in the Workspace Myeclipse中删除Blog_bug工程时没有勾选D…...
做地方网站论坛赚钱/seo标题优化步骤
虽然Web应用程序是目前最热门的主题,但它们的编程模型有别于传统的、非Web的应用程序,这为开发者带来了新的挑战。传统应用程序具有相当确定的控制流,但Web应用程序要针对不由自己控制的外部事件(HTTP请求)来采取行动和…...