C++_vector类

       

目录

一、vector的模拟实现

1、vector的组成结构

2、vector尾插数据 

2.1 析构函数 

3、迭代器实现

4、resize

5、删除数据 

5.1 迭代器失效 

6、指定位置插入数据

6.1 迭代器失效

7、迭代器构造和resize构造

8、深浅拷贝

结语:


前言:

        vector类是STL(标准模板库)中的八大容器之一,而STL属于C++标准库的一部分,所以可以直接使用vector。他的作用类似于数组,是用一段连续的空间来存储元素,因此可以支持下标访问各个元素,其中元素的类型可以是int、char...类型以及自定义类型,所以vector类实际上是一个类模板。但是vector类对空间内存的管理比数组更加严格,且使用起来较数组更简便,因为vector是一个类很多功能都已封装完成,可以直接提供用户使用。

一、vector的模拟实现

1、vector的组成结构

        vector类是由三个成员指针变量构成的,可以把这三个成员命名为:_start、_finish、_end_of_storage。

        1、其中_start的作用类似于数组名,表示首元素地址,因此是用_start来开辟空间的。

        2、而_finish指向最后一个元素的下一个位置。他的作用是减去_start可以得到当前空间的元素个数。(通过指针-指针得到整数的方式

        3、_end_of_storage指向整个空间的末尾处的下一个位置。他的作用是减去_start可以得到空间容量。

        具体示意图如下:

2、vector尾插数据 

        有了上面的成员介绍就可以写一个简单的尾插函数,代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
using namespace std;
#include<assert.h>namespace ZH
{template<class T>class vector{public:typedef T* iterator;vector()//构造函数{}size_t size()const//得到元素个数{return _finish - _start;}size_t capacity()const//得到空间大小{return _end_of_storage - _start;}void reserve(size_t n)//扩容函数{if (n > capacity()){T* temp = new T[n];size_t poi = _finish-_start;//先把_start和_finish之间的距离记录下来if (_start != nullptr){memcpy(temp, _start, sizeof(T) * size());//拷贝数据delete[] _start;}_start = temp;//更新_start的指向_finish = _start + poi;_end_of_storage = _start + n;}}void push_back(const T& val){if (_finish == _end_of_storage)//相等说明当前容量不够{reserve(capacity()==0?4:capacity() * 2);//扩容}*_finish = val;//尾插_finish++;}T& operator[](size_t i)//解引用运算符重载{assert(i < size());//检查越界return _start[i];}private:iterator _start = nullptr;//缺省值赋予空iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}int main()
{//实例化对象v1ZH::vector<int> v1;//尾插五个数v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << endl;}return 0;
}

  运行结果:

        上述代码需要注意的是:扩容时采用的是异地扩容,因此要注意_start值的变化对_start与_finish之间距离的影响。如下图:

2.1 析构函数 

        因为是_start申请的空间,因此只需要delete _start即可。

~vector(){delete[] _start;_start = _finish = _end_of_storage = nullptr;}

3、迭代器实现

        vector的迭代器可以看作是一个指针,迭代器实际上就是通过两个成员函数返回的指针实现的,这两个成员函数分别是begin()和end(),一个返回首元素地址,一个返回末尾元素的下一个地址。然后用一个指针来接收他们的返回值,我们只需要把这个指针封装成迭代器的写法即可。

        迭代器实现代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
using namespace std;
#include<assert.h>namespace ZH
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector()//构造函数{}size_t size()const//得到元素个数{return _finish - _start;}size_t capacity()const//得到空间大小{return _end_of_storage - _start;}void reserve(size_t n)//扩容函数{if (n > capacity()){T* temp = new T[n];size_t poi = _finish - _start;//先把_start和_finish之间的距离记录下来if (_start != nullptr){memcpy(temp, _start, sizeof(T) * size());//拷贝数据delete[] _start;}_start = temp;//更新_start的指向_finish = _start + poi;_end_of_storage = _start + n;}}void push_back(const T& val){if (_finish == _end_of_storage)//相等说明当前容量不够{reserve(capacity() == 0 ? 4 : capacity() * 2);//扩容}*_finish = val;//尾插_finish++;}//普通版本迭代器函数iterator begin(){return _start;}iterator end(){return _finish;}//const版本迭代器的函数const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}private:iterator _start = nullptr;//缺省值赋予空iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}int main()
{//实例化对象v1ZH::vector<int> v1;//尾插五个数v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);//普通迭代器ZH::vector<int>::iterator it = v1.begin();while (it != v1.end()){(*it)++;cout << *it << " ";it++;}cout << endl;//const版本的迭代器ZH::vector<int>::const_iterator cit = v1.begin();while (cit != v1.end()){//(*cit)++;//const版本迭代器不能通过迭代器修改对象中的内容cout << *cit << " ";cit++;}return 0;
}

        运行结果:

4、resize

void resize(size_t n, const T& t = T())
//n表示期望的元素个数
//t表示补齐元素的值

        resize的作用是控制元素个数的多少,如果n大于当前元素的总数,则会在后面补齐元素,并且补齐元素的值为t,如果n大于该对象的容量,则会自动扩容。当n小于当前元素的总数,则该对象内的有效元素个数为n个(注意resize不会进行缩容)。

        模拟实现resize:

#include<iostream>
using namespace std;
#include<assert.h>namespace ZH
{template<class T>class vector{public:typedef T* iterator;vector()//构造函数{}size_t size()const//得到元素个数{return _finish - _start;}size_t capacity()const//得到空间大小{return _end_of_storage - _start;}void reserve(size_t n)//扩容函数{if (n > capacity()){T* temp = new T[n];size_t poi = _finish - _start;//先把_start和_finish之间的距离记录下来if (_start != nullptr){memcpy(temp, _start, sizeof(T) * size());//拷贝数据delete[] _start;}_start = temp;//更新_start的指向_finish = _start + poi;_end_of_storage = _start + n;}}void push_back(const T& val){if (_finish == _end_of_storage)//相等说明当前容量不够{reserve(capacity() == 0 ? 4 : capacity() * 2);//扩容}*_finish = val;//尾插_finish++;}void resize(size_t n, const T& t = T())//匿名对象具有常属性{if (n < size()){_finish = _start + n;}else{if (n > capacity())reserve(n);while (_finish != _start + n){*_finish = t;_finish++;}}}//普通版本迭代器函数iterator begin(){return _start;}iterator end(){return _finish;}private:iterator _start = nullptr;//缺省值赋予空iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}int main()
{//实例化对象v1ZH::vector<int> v1;//尾插五个数v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.resize(8);//验证n大于元素总数ZH::vector<int>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";it++;}cout << endl;v1.resize(3);//验证n小于元素总数it = v1.begin();while (it != v1.end()){cout << *it << " ";it++;}return 0;
}

         运行结果:

5、删除数据 

         vector类可以看作是一个数组,数组的删除数据有尾删和指定位置删除,尾删就很简单了,直接让_finish--即可,因为打印数据时不会打印_finish的位置,当指针_finish指向最后一个元素,表示最后一个元素不打印,则达到了间接尾插。

        而指定位置删除就稍微复杂些,比如删除第一个元素,那么要让后面的元素整体往前移到一位,最后再让_finish--,这样挪动数据的消耗是很大的。

        指定位置删除数据代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
using namespace std;
#include<assert.h>namespace ZH
{template<class T>class vector{public:typedef T* iterator;vector()//构造函数{}size_t size()const//得到元素个数{return _finish - _start;}size_t capacity()const//得到空间大小{return _end_of_storage - _start;}void reserve(size_t n)//扩容函数{if (n > capacity()){T* temp = new T[n];size_t poi = _finish - _start;//先把_start和_finish之间的距离记录下来if (_start != nullptr){memcpy(temp, _start, sizeof(T) * size());//拷贝数据delete[] _start;}_start = temp;//更新_start的指向_finish = _start + poi;_end_of_storage = _start + n;}}void push_back(const T& val){if (_finish == _end_of_storage)//相等说明当前容量不够{reserve(capacity() == 0 ? 4 : capacity() * 2);//扩容}*_finish = val;//尾插_finish++;}iterator erase(iterator pos)//指定位置删除,并返回当下位置{//检查pos是否合格assert(pos >= _start);assert(pos < _finish);iterator start = pos;while (start!=_finish-1){*start = *(start + 1);//挪动数据start++;}_finish--;return pos;}//普通版本迭代器函数iterator begin(){return _start;}iterator end(){return _finish;}private:iterator _start = nullptr;//缺省值赋予空iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}int main()
{//实例化对象v1ZH::vector<int> v1;//尾插五个数v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);//删除ZH::vector<int>::iterator it = v1.begin()+1;//删除第二个元素v1.erase(it);//使用完it后,正常来说it是会失效的v1.erase(it);//删除第二个元素后,后面的元素往前挪动,则it指向的是第三个元素v1.erase(v1.end() - 1);//删除最后一个元素it = v1.begin();//it失效了需要重新赋值while (it != v1.end()){cout << *it << " ";it++;}return 0;
}

         运行结果:

5.1 迭代器失效 

         一般而言,用一个迭代器进行erase后,该迭代器会发生失效,原因就是会出现以下情况:

        因此经过erase之后的迭代器会认为是失效的,即不能继续使用该迭代器。

6、指定位置插入数据

        指定位置插入数据就是将该位置之后的所有数据往后面挪一位,然后直接把要插入的数据放到该位置即可。(注意扩容问题

        插入代码如下:

#include<iostream>
using namespace std;
#include<assert.h>namespace ZH
{template<class T>class vector{public:typedef T* iterator;vector()//构造函数{}size_t size()const//得到元素个数{return _finish - _start;}size_t capacity()const//得到空间大小{return _end_of_storage - _start;}void reserve(size_t n)//扩容函数{if (n > capacity()){T* temp = new T[n];size_t poi = _finish - _start;//先把_start和_finish之间的距离记录下来if (_start != nullptr){memcpy(temp, _start, sizeof(T) * size());//拷贝数据delete[] _start;}_start = temp;//更新_start的指向_finish = _start + poi;_end_of_storage = _start + n;}}void push_back(const T& val){if (_finish == _end_of_storage)//相等说明当前容量不够{reserve(capacity() == 0 ? 4 : capacity() * 2);//扩容}*_finish = val;//尾插_finish++;}void Insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage)//相等说明当前容量不够{size_t len = pos - _start;//记录pos与_start之间的距离reserve(capacity() == 0 ? 4 : capacity() * 2);//扩容pos = _start + len;//依靠len更新pos的新位置}iterator end = _finish-1;while (end>=pos){*(end+1) = *end;end--;}*pos = val;_finish++;}//普通版本迭代器函数iterator begin(){return _start;}iterator end(){return _finish;}private:iterator _start = nullptr;//缺省值赋予空iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}int main()
{//实例化对象v1ZH::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.Insert(v1.begin()+2, 30);ZH::vector<int>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";it++;}cout << endl;return 0;
}

         运行结果:

         扩容导致的问题如下图:

6.1 迭代器失效

        用一个迭代器进行插入后,该迭代器也会失效,原因是虽然Insert函数里面的pos进行了位置的更新,但是形参的改变不影响实参,外面的pos实质上还是指向原来空间的位置,此时的pos就处于野指针行为,因此不能进行对其进行使用了。

7、迭代器构造和resize构造

        vector类的构造方式除了上面的默认构造还有迭代器构造和resize构造,即实例化对象就能让该对象中拥有数据。

        两种构造方式代码如下:

#include<iostream>
using namespace std;
#include<assert.h>namespace ZH
{template<class T>class vector{public:typedef T* iterator;vector()//构造函数{}vector(size_t n, const T& t = T())//resize构造{resize(n, t);}template<class Inputinteraor>vector(Inputinteraor left, Inputinteraor right)//迭代器构造{size_t sz = right - left;reserve(sz);while (left != right){push_back(*left);left++;}}void push_back(const T& val){if (_finish == _end_of_storage)reserve(capacity() == 0 ? 4 : capacity() * 2);*_finish = val;_finish++;}void resize(size_t n, const T& t = T())//匿名对象具有常属性{if (n < size()){_finish = _start + n;}else{if (n > capacity())reserve(n);while (_finish != _start + n){*_finish = t;_finish++;}}}size_t size()const//得到元素个数{return _finish - _start;}size_t capacity()const//得到空间大小{return _end_of_storage - _start;}void reserve(size_t n)//扩容函数{if (n > capacity()){T* temp = new T[n];size_t poi = _finish - _start;//先把_start和_finish之间的距离记录下来if (_start != nullptr){memcpy(temp, _start, sizeof(T) * size());//拷贝数据delete[] _start;}_start = temp;//更新_start的指向_finish = _start + poi;_end_of_storage = _start + n;}}//普通版本迭代器函数iterator begin(){return _start;}iterator end(){return _finish;}private:iterator _start = nullptr;//缺省值赋予空iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}int main()
{ZH::vector<int> v1(10u, 6);//resize构造ZH::vector<int> v2(v1.begin(),v1.end());//迭代器构造ZH::vector<int>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";it++;}cout << endl;ZH::vector<int>::iterator it2 = v2.begin();while (it2 != v2.end()){cout << *it2 << " ";it2++;}cout << endl;return 0;
}

        运行结果:

8、深浅拷贝

        若我们自己不写拷贝构造则系统会自动生成一个拷贝构造,但是系统自动生成的拷贝构造只能完成浅拷贝,即一些成员变量的值拷贝,但是这里的vector涉及到空间的开辟,因此不能用浅拷贝完成vector类型的拷贝,原因如下图:

        我们所期望的是v2指向一块属于自己的空间,如下图:


         但是即便是v2有一块属于自己的空间也不是完全解决了问题,因为vector的类型可以是自定义类型,这时候如果当vector的类型是string类型,那么vector中的每个元素都是string类型,则每个元素自己内部又会新开辟一块空间,这时候就是深拷贝的问题了。

        示意图如下:

        我们所期望的是每个自定义元素也指向一块属于该元素的空间:


        因此当把v1里的元素拷贝给到v2的新空间时,元素之间的拷贝必须也是深拷贝,双重深拷贝代码如下: 

#include<iostream>
using namespace std;
#include<assert.h>namespace ZH
{template<class T>class vector{public:typedef T* iterator;vector()//构造函数{}void push_back(const T& val){if (_finish == _end_of_storage)reserve(capacity() == 0 ? 4 : capacity() * 2);*_finish = val;_finish++;}size_t size()const//得到元素个数{return _finish - _start;}size_t capacity()const//得到空间大小{return _end_of_storage - _start;}void reserve(size_t n)//扩容函数{if (n > capacity()){T* temp = new T[n];size_t poi = _finish - _start;//先把_start和_finish之间的距离记录下来if (_start != nullptr){memcpy(temp, _start, sizeof(T) * size());//拷贝数据delete[] _start;}_start = temp;//更新_start的指向_finish = _start + poi;_end_of_storage = _start + n;}}vector(const vector<T>& val)//深拷贝构造{_start = new T[val.capacity()];for (size_t i = 0; i < val.size(); i++){//会调用string的运算符重载,而sting的运算符重载本身就是深拷贝_start[i] = val._start[i];}_finish = _start + val.size();_end_of_storage = _start + val.capacity();}~vector()//析构函数{delete[] _start;_start = _finish = _end_of_storage = nullptr;}//普通版本迭代器函数iterator begin(){return _start;}iterator end(){return _finish;}private:iterator _start = nullptr;//缺省值赋予空iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}int main()
{ZH::vector<string> v1;v1.push_back("hello");v1.push_back("hello");ZH::vector<string> v2 = v1;//双重深拷贝构造//打印v2的值ZH::vector<string>::iterator it = v2.begin();while (it != v2.end()){cout << *it << " ";it++;}cout << endl;return 0;
}

        运行结果:

        这里值得注意的是代码可以正常运行,意味着析构的时候没有出问题,即没有出现同一块空间被析构两次的情况。 

结语:

        以上就是关于vector的模拟实现,通过模拟实现可以帮助我们更深层次的了解vector类,vector类实质上就是一个动态的数组,只不过用起来更加便捷。最后希望本文可以给你带来更多的收获,如果本文对你起到了帮助,希望可以动动小指头帮忙点赞👍+关注😎+收藏👌!如果有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!

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

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

相关文章

vue前端开发自学demo-input标签数据双向绑定

vue前端开发自学demo-input标签数据双向绑定&#xff01;今天为大家 展示的内容是&#xff0c;前端开发常见的&#xff0c;form表单里面的&#xff0c;一些输入数据的元素&#xff0c;动态绑定数据的案例。比如input,以及checkbox的状态绑定案例。 首先&#xff0c;老规矩&…

【人工智能Ⅰ】实验11:支持向量机

实验11 支持向量机 一、实验目的 1&#xff1a;了解支持向量机的结构和原理。 2&#xff1a;应用支持向量机建立训练模型&#xff0c;对模型进行评估。 二、实验内容和要求 【实验内容】 选择支持向量机&#xff0c;对花卉图像或玉米果穗图像进行分类。花卉图像包括玫瑰&a…

关于LINUX操作系统异常宕机重启的分析思路

一、先搞清楚现状 当收到系统宕机告警或者故障反馈时&#xff0c;需要先对情况进行核实。比如检查系统启动时间&#xff0c;是不是真实发生了重启&#xff1f;如果重启了&#xff0c;什么时间点发生的重启&#xff1f;重启了几次&#xff1f;重启之前有无变更操作&#xff1f;…

PyTorch|构建自己的卷积神经网络——nn.Sequential()

之前在构建神经网络时&#xff0c;我们一般是采用这种方式&#xff0c;就像这样&#xff1a; class Network1(nn.Module): def __init__(self): super(Network1,self).__init__() self.conv1 nn.Conv2d(in_channels3, out_channels6, kernel_size5) …

【控制篇 / 策略】(7.4) ❀ 03. 地理地址对象在路由中的应用 ❀ FortiGate 防火墙

【简介】如何做到访问国内走Wan1&#xff0c;访问国际走Wan2 &#xff1f;当企业有多条宽带&#xff0c;特别是有国际专线的时候&#xff0c;这个需求就很普遍了。通过地理地址对象可以快速的解决这些问题。 策略路由 当我们有多条宽带的时候&#xff0c;我们有两种方法分流&am…

C++的虚基类

前言 本文介绍C的虚基类 先看一个问题 先看一段代码 #include <iostream> class A { public:int a 1; };class B1:public A { public:int b1 2; };class B2 :public A { public:int b2 3; };class C1:public B1,public B2 { public:int c1 4; };int main(int arg…

每日汇评:黄金多头能否在美国CPI数据发布后占有主动权?

黄金价格再次在2020美元附近找到支撑&#xff0c;因为所有人都在关注美国的通胀数据&#xff1b; 尽管最近美国国债收益率有所上升&#xff0c;但美元仍进一步下跌&#xff1b; 金价保持在21日移动均线和50日移动均线之间&#xff0c;等待区间突破&#xff1b; 在周四早盘的亚洲…

SIT1050ISO具有隔离功能,1Mbps,高速 CAN 总线收发器

➢ 完全兼容“ ISO 11898 ”标准&#xff1b; ➢ 内置过温保护&#xff1b; ➢ 100kV/s 瞬态抗扰度&#xff1b; ➢ 显性超时功能&#xff1b; ➢ -40V 至 40V 的总线故障保护&#xff1b; ➢ I/O 电压范围支持 3.3V 和 5V MCU &#xff1b; ➢ 低环路延迟…

解决原生微信小程序获取关联公众号的code(不是wx.login的code)来获取公众号的openId

解决步骤 以下是使用 web-view 并配配合微信公众号提供的 网页授权 来实现 1、在小程序中做一个web-view页面&#xff0c;页面中只需要写微信 网页授权的链接就行了&#xff0c;注意appid请自行替换&#xff08;公众号的&#xff09;。 onLoad() {this.setData({src: https://o…

Android SDK环境搭建[图解]; 解决问题Done. Nothing was installed.

安装SDK Android SDK环境搭建 依赖java环境,需要自备Java环境 (100%实操成功) 目录 1. 解压&#xff1a;解压到非中文无特殊字符的目录 2. 双击&#xff1a;SDK Manager.exe&#xff0c;不要选全部!不要选全部!不要选全部!(会下很久) 3. 然后勾选组件​ 4. 设置环境变量 …

UM2003A 一款200 ~ 960MHz ASK/OOK +18dBm 发射功率的单发射芯片

UM2003A 是一款工作于 200 ~ 960MHz 频段的单片集成、高性能、可独立运行的 OOK 发射器。内部集成的 OTP 方便用户对各种射频参数以及特色功能进行编程。该芯片以其高集成度和低功耗的设计&#xff0c;特别适用于低成本&#xff0c;低功耗&#xff0c;电池驱动的无线发射应用。…

【TypeScript】入门基础知识

目前在做项目的技术栈是 reacttypescript&#xff0c;之前只知道 ts 是 js 的扩展&#xff0c;增加了类型检查&#xff0c;但是没有仔细的学过&#xff0c;纯纯看别人代码上手 anyscript&#xff08;这很难评...&#xff09;。趁着最近空闲&#xff0c;就学习一下 ts 的基础知识…

章鱼网络 2023 年全回顾|暨12月进展报告

2023年&#xff0c;章鱼网络轻装上阵&#xff0c;身处加密行业的低谷中砥砺前行。 12月17日&#xff0c;经过整整1年时间的开发和打磨&#xff0c;章鱼网络在重磅上线 Octopus 2.0&#xff0c;即 $NEAR Restaking 和 NEAR-IBC&#xff0c;获得了社区和市场的一致认可&#xff…

Java中多线程二

抢占调度模型 概述&#xff1a;优先让优先级高的线程使用 CPU &#xff0c;如果线程的优先级相同&#xff0c;那么随机会选择一个&#xff0c;优先级高的线程获取的 CPU 时间片相对多一些 Thread 类中一些关于线程的方法 方法简述public final int getPriority()返回此线程的优…

自动化控制面板-1Panel

一、1Panel自动化控制面板 官网地址 1Panel 可以实现&#xff1a; 快速建站、高效管理、安全可靠、一键备份、应用商店 快速建站&#xff1a;深度集成 Wordpress 和 Halo&#xff0c;域名绑定、SSL 证书配置等一键搞定&#xff1b;高效管理&#xff1a;通过 Web 端轻松管理 …

Docker启动报错:No chain/target/match by that name 处理

一、问题描述 某次OS升级重启后&#xff0c;发现docker redis实例无法启动&#xff0c;报错如下&#xff1a; Error response from daemon: driver failed programming external connectivity on endpoint vpm.redis.2 (f4b70fef65000bcacb574ee59e65d9b7a25f2abfa5dec0be9b74…

阿里云实时计算企业级状态存储引擎 Gemini 技术解读

本文整理自阿里云 Flink 存储引擎团队李晋忠&#xff0c;兰兆千&#xff0c;梅源关于阿里云实时计算企业级状态存储引擎 Gemini 的研究&#xff0c;内容主要分为以下五部分&#xff1a; 流计算状态访问的痛点企业级状态存储引擎GeminiGemini 性能评测&线上表现结语参考 一、…

2024年最新ChemiCloud优惠75%折扣WordPress外贸主机

ChemiCloud怎么样&#xff1f;ChemiCloud好不好&#xff1f;ChemiCloud是一家成立于2016年的云虚拟主机提供商&#xff0c;他们在全球范围内拥有多个机房&#xff0c;并以其出色的性价比而备受赞誉。他们整合了许多先进技术&#xff0c;包括Digital Ocean SSD云服务器、LiteSpe…

云计算任务调度仿真03

前面陆续分享了基于policy gradient和DQN实现的深度强化学习任务调度仿真&#xff0c;上次的DQN没有实现fix-qtarget和experience replay&#xff0c;这次再分享实现了这两个方法的DQN任务调度仿真。 经验重放&#xff0c;定义存储和存放次序&#xff0c;这里也可以自行修改 de…

提升测试效率,轻松并行运行测试——探秘Pytest插件pytest-xdist

在软件开发中&#xff0c;测试是确保代码质量的重要一环。然而&#xff0c;随着项目规模的增大&#xff0c;测试用例的数量也随之增多&#xff0c;测试的执行时间可能成为一个瓶颈。为了解决这个问题&#xff0c;Pytest提供了丰富的插件生态系统&#xff0c;其中 pytest-xdist …