【C++】vector 模拟实现
vector
- vector 容器
- vector 基本使用
- vector 定义
- 库中各类接口的使用
- 迭代器
- 容量相关接口
- 元素访问相关接口
- 元素修改相关接口
- 模拟实现 vector
- 前期准备
- 构造与析构
- 赋值运算符重载
- 迭代器相关
- 容量相关
- 元素访问相关
- 元素的修改相关
- 二维数组的创建
- 对于自定义类型数据的测试
vector 容器
C++ STL 中的 vector 就类似于 C 语言当中的数组,但是 vector 又拥有很多数组没有的接口,使用起来会更加的方便。
相比于 STL 中的 string ,vector 可以定义不同的数据类型
vector 基本使用
vector 定义
template < class T, class Alloc = allocator > class vector;
方式一:创建 vector 对象,不进行初始化
vector (const allocator_type& alloc = allocator_type());
方式二:创建 vector 对象,容量为 n,并赋值为 val
vector (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
方式三:创建 vector 对象,并采用区间赋值
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
方式四:拷贝构造
vector (const vector& x);
代码演示:
vector<int> v; //定义一个 int 类型变量vector<int> v0{ 1,2,3,4,5,6,7,8,9 }; //定义 int 数组并进行列表赋值PrintVector(v0);vector<int> v1(10, 5); //定义一个 int 类型数组,数组内容为 10 个 5PrintVector(v1);int arr[] = { 1,2,3,4,5,6 }; //区间构造vector<int> v2(arr, arr + sizeof(arr) / sizeof(arr[0]));PrintVector(v2);string s("hello"); //采用迭代器构造vector<char> v3(s.begin(), s.end());PrintVector(v3);vector<char> v4(v3); //拷贝构造PrintVector(v4);
定义一个打印函数可以很明显的观察到定义结果:
template<class T>
void PrintVector(const vector<T>& v)
{for (auto e : v)cout << e << " ";cout << endl;
}
库中各类接口的使用
迭代器
迭代器的本质是指针,其指针指向如下图:
begin() 指向空间起始位置,end() 指向最后一个有效元素的下一个位置
rbegin() 指向最后一个有效元素的下一个位置,rend() 指向空间的起始位置。
代码演示:
容量相关接口
代码演示:
(1)测试 size() 、capacity()、以及 resize()
vector<int> v{ 1,2,3,4,5,6 };PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;//resize 修改有效元素个数v.resize(10, 0); //将有效元素个数修改为 10,多余空间用 0 来进行填充PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.resize(20);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.resize(4); //有效元素个数缩小为 4PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;
可以发现:
resize 修改有效元素个数时,size 会进行相应的扩大或缩小变化,capacity 不一定会变化(有效元素增多时,若容量足够则capacity不变,否则会扩容;有效元素减少时,capacity 不变)
(2)测试 reserve
vector<int> v{ 1,2,3,4,5,6 };PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;//reserve 修改容量v.reserve(10);PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.reserve(30);PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.reserve(10);PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;
可以发现:
reserve 修改容量时,size 是不会发生变化的(因为有效元素个数不变),若空间容量扩大则 capacity 会相应的进行扩大,若空间容量缩小时 capacity 是不会发生变化的
(3)测试 empty
empty 是进行判空的接口
元素访问相关接口
(1)下标运算符访问 operator[]
越界测试:越界触发 assert 异常
(2)at 访问
越界测试:越界抛出 out_of_range 异常
(3)获取首尾元素 front back
元素修改相关接口
(1)尾插 push_back
(2)尾删 pop_back
(3)任意位置插入 insert
vector<int> v{ 1,2,3 };cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;v.insert(v.begin(), 100); //在起始位置插入 100PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;int arr[] = { 0,200,300,400 };v.insert(v.begin(), arr, arr + sizeof(arr) / sizeof(arr[0])); //起始位置插入arr数组中元素PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;v.insert(v.end(), 9); //尾部插入元素 9----------------同理也可以插入数组 arrPrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;v.insert(v.end(), arr, arr + sizeof(arr) / sizeof(arr[0])); //尾部插入arr数组中元素PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;
(4)任意位置删除 erase
(5)清空 clear
模拟实现 vector
前期准备
迭代器的本质就是指针,模拟实现 vector 容器,我们需要定义三个指针 :指向起始位置 start,指向最后一个有效元素的下一个位置 finish ,指向容器最后一个位置 endofstorage:
namespace xx { //自定义命名空间template<class T> //定义模板类型class vector{public:typedef T* iterator; //迭代器 等价于 T 类型指针private:iterator start; //空间起始位置iterator finish; //最后一个有效元素的下一个位置iterator endofstorage; //最后一个容量空间位置};
}
构造与析构
构造函数
(1)默认无参构造
vector() :start(nullptr), finish(nullptr), endofstorage(nullptr){}
(2)构造具有 n 个对象值为 val 的容器 (数据类型为模板类型 T)
vector(int n, const T& val = T()){start = new T[n]; //创建新空间for (size_t i = 0; i < n; ++i) {start[i] = val; //对空间进行赋值操作}finish = start + n; //修改 finish 指向---最后一个有效元素的下一个位置endofstorage = finish; //修改容量指针}
注意:
第二个参数 val 是一个缺省参数,对于内置类型,T() 的值为 0;对于自定义类型, T() 调用的是该自定义类型的默认构造函数
因此,对于自定义类型一定要有默认的构造函数,否则会报错
(3)使用迭代器进行构造
template<class Iterator>vector(Iterator first, Iterator last) //区间构造{auto it = first;size_t n = 0;while (it != last) {++it;n++; //统计区间中元素个数}start = new T[n]; //开辟空间finish = start;while (first != last) { //进行赋值*finish = *first;++first; ++finish;}endofstorage = finish; //修改容量指针}
(4)拷贝构造
vector(const vector<T>& v){size_t n = v.size(); //记录 v 中元素个数start = new T[n]; //创建新空间for (size_t i = 0; i < n; ++i){start[i] = v[i]; //进行赋值操作}finish = start + n; //修改指向endofstorage = finish;}
新写法(参考上一篇博客深浅拷贝问题)
vector(const vector<T>& v){vector<T> tmp(v.begin(),v.end()); //定义临时对象--调用迭代器构造方法this->swap(tmp); //进行资源交换}
析构函数
~vector(){if (start) {delete[] start;start = finish = endofstorage = nullptr;}}
测试代码
void MyvectorTest0()
{xx::vector<int> v1;xx::vector<int> v2(10, 5); int arr[] = { 1,2,3,4,5 }; //区间构造xx::vector<int> v3(arr, arr + sizeof(arr) / sizeof(arr[0]));xx::vector<int> v4(v2); //拷贝构造//遍历一:for (int i = 0; i < v2.size(); ++i) {cout << v2[i] << " ";}cout << endl;//遍历二:for (auto e : v3)cout << e << " ";cout << endl;//遍历三:auto it = v4.begin();while (it != v4.end()) {cout << *it << " ";++it;}cout << endl;}
会发现在运行代码时候出现的问题:
分析:
在构造 v2 时候,会调用区间构造方法,进行参数类型的推演,由于构造 v2 的两个参数都是 int 类型,故编译器会根据类型推演的结果来选择合适的构造方法,又因为构造 n 个值为 val 的构造方法中参数类型为 size_t , int,所以编译器认为类型不匹配,排除该构造方法,选用了迭代器区间的构造方法(参数类型实例化之后都为 int 类型),因此,为了实现构造 n 个值为 val 的空间构造,我们需要对构造函数进行一定的修改,使得其调用更准确:
赋值运算符重载
vector<T>& operator=(vector<T> v) { //因为参数是传值类型,故在传参过程中会进行一次拷贝构造的调用//赋值运算符重载this->swap(v); //直接进行交换(可以参考上一篇博客中深浅拷贝内容)return *this;}
迭代器相关
//迭代器iterator begin(){return start;}iterator end(){return finish;}
容量相关
(1)size、capacity、empty 的实现
size_t size()const {return finish - start;}size_t capacity()const {return endofstorage - start;}bool empty()const {return finish == start;}
(2)resize :修改有效元素个数
void resize(size_t newsize, const T&val = T()){size_t oldsize = size();if (newsize <= oldsize) { //缩小有效元素finish = start + newsize; //容量不变}else {//有效元素增大//需要扩容size_t cap = capacity();if(newsize > cap)reserve(newsize);for (size_t i = oldsize; i < newsize; ++i) {//多出来的空间填充start[i] = val;}finish = start + newsize;//endofstorage = finish;}}
(3)reserve:修改容量
void reserve(size_t newcapacity){size_t oldcapacity = capacity();if (newcapacity > oldcapacity) {//开辟新空间T* tmp = new T[newcapacity];if (start) {拷贝元素:memcpy(内存拷贝--------将一段空间中的内容原封不动的拷贝到新空间----浅拷贝) 按字节拷贝涉及到资源管理时,memcpy 属于浅拷贝//memcpy(tmp, start, sizeof(T)*size());for (size_t i = 0; i < size(); ++i) {tmp[i] = start[i];}//释放旧空间delete[] start;}size_t sz = size();start = tmp;finish = start + sz; //**********endofstorage = start + newcapacity;}}
代码测试:
(1)测试 resize (含 size, capacity 的测试)
(2)测试 reserve
元素访问相关
(1)获取首尾元素 front back
T& front(){return *start;}const T& front()const{return *start;}T& back(){return *(finish - 1);}const T& back()const{return *(finish - 1);}
(2)下标访问
T& operator[](size_t index){assert(index < size()); //注意区分异常处理方式return start[index];}const T& operator[](size_t index)const{assert(index < size());return start[index];}
(3)at 访问
T& at(size_t index){if (index >= size())throw out_of_range("vector at method: index out_of_range"); //抛出异常return start[index];}const T& at(size_t index)const{if (index >= size())throw out_of_range("vector at method: index out_of_range");return start[index];}
代码测试:
元素的修改相关
(1)尾插
void push_back(const T& val){//进行尾插,判断容量是否足够if (finish == endofstorage) {reserve(capacity() * 2 + 3); //按照2倍进行扩容}*finish = val;++finish;}
(2)尾删
void pop_back(){//进行尾删if (empty())return;--finish; //直接修改尾指针}
(3)任意位置插入
//insert 插入元素的时间复杂度 O(n)iterator insert(iterator pos, const T&val){//判断插入位置的合法性if (pos < begin() || pos > end())return end();//任意位置进行插入if (finish == endofstorage)reserve(capacity() * 2); //扩容auto it = finish - 1;while (it >= pos) { //元素后移*(it + 1) = *it;--it;}*it = val; //当前 it 指向的就是 pos 的位置++finish;return it; //返回新插入的元素的位置}
(4)任意位置删除
删除单个元素:
iterator erase(iterator pos){//删除任意位置元素if (empty())return end();if (pos < begin() || pos >= end())return end();//位置合理auto it = pos;while (it != end() - 1) //end() 表示最后一个有效元素的下一个位置{*it = *(it + 1); //元素前移--it;}--finish; //删除元素需要修改尾指针位置return pos;}
删除区间元素:
iterator erase(iterator start, iterator last){if (empty())return end();if (start < begin() || start >= end())return end();//位置合法, 删除区间auto beg = start;auto en = last;int n = last - start; //要删除的元素个数while (en != end()){*beg = *en;++beg; ++en;//--finish;}finish -= n;return start; //返回删除的区间首元素位置}
(5)清空
void clear(){erase(begin(), end());}
(6)交换函数
void swap(vector<T>& v){std::swap(start, v.start);std::swap(finish, v.finish);std::swap(endofstorage, v.endofstorage);}
测试代码:
(1)测试尾插尾删:
(2)测试任意位置的插入删除:
(3)清空:
二维数组的创建
创建一个五行六列数组,数组中元素值都为 8:
void MyvectorTest3()
{xx::vector<xx::vector<int>> vv(5, xx::vector<int>(6, 8)); //创建有 5 个元素的数组,数组中元素用 vector<int>(6,8) 来进行填充for (size_t i = 0; i < vv.size(); ++i){for (size_t j = 0; j < vv[i].size(); ++j)cout << vv[i][j] << " ";cout << endl;}
}
对于自定义类型数据的测试
上述的测试我们都是基于内置类型int数据的测试,发现代码可以正确运行没有报错,那针对于自定义类型数据是否正确呢?
(1)定义一个日期类:
class Date {
public:Date(int year = 1990, int month = 1, int day = 20){_year = year;_month = month;_day = day;}Date(const Date& d){//拷贝构造_year = d._year;_month = d._month;_day = d._day;}~Date() {}
private:int _year;int _month;int _day;
};void MyvectorTest4()
{xx::vector<Date> d; //定义 Date 类型数组d.push_back(Date(2023, 1, 1)); //插入元素--------Date 构造函数必须为带缺省值的构造方法d.push_back(Date(2023, 1, 2));d.push_back(Date(2023, 1, 3));d.push_back(Date(2023, 1, 4));d.push_back(Date(2023, 1, 5));cout << d.size() << endl;
}
运行改代码显式可以正确运行,因为 Date 类不存在资源的处理,那针对于 string 类是否正常?
我们来试试:
(2)定义 string 类:
class String {
public:String(const char* str=""):_str(nullptr){//构造if (nullptr == str)str = "";_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s):_str(new char[strlen(s._str)+1]){//拷贝构造strcpy(_str, s._str);}String& operator=(const String& s){if (this != &s) {//不是给自己的赋值char* tmp = new char[strlen(s._str) + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;}return *this;}//String& operator=(const String s)//{// if (this != &s) {// //新写法// this->swap(s._str);// }// return *this;//}~String(){if (_str) {delete[] _str;_str = nullptr;}}
private:char* _str;
};void MyvectorTest5()
{xx::vector<String> s;s.push_back("hello");s.push_back("welcom");s.push_back("come on");cout << s.size() << endl;s.push_back("hahahha"); //此时需要进行扩容发生报错----------memcpy是属于浅拷贝}
运行发现,在最后一次尾插时发生了错误,我们来看看是什么原因导致的:
因为在第四次尾插时候需要进行扩容,因此产生了错误
往下运行一步就会发现问题所在了:
发现,在进行 memcpy 拷贝时候发生了浅拷贝,即将原空间内容原封不动的拷贝到新空间,这就导致了新空间共享旧空间的地址,会造成内存泄漏
因此,在扩容时候我们需要按元素将旧空间中元素交给新空间,而不是将地址空间也赋给新空间
进行修改:
修改之后程序可以正常运行。
_CrtDumpMemoryLeaks(); //检测内存泄漏
该章节完整代码:
添加链接描述
本篇内容就分享到这里啦!!!
学习编程的道路很长,要注重自我实践与验证,欢迎读者评论探讨~
相关文章:

【C++】vector 模拟实现
vectorvector 容器vector 基本使用vector 定义库中各类接口的使用迭代器容量相关接口元素访问相关接口元素修改相关接口模拟实现 vector前期准备构造与析构赋值运算符重载迭代器相关容量相关元素访问相关元素的修改相关二维数组的创建对于自定义类型数据的测试vector 容器 C S…...

canvas初体验
canvas介绍 Canvas 最初由Apple于2004 年引入,用于Mac OS X WebKit组件,为仪表板小部件和Safari浏览器等应用程序提供支持。后来,它被Gecko内核的浏览器(尤其是Mozilla Firefox),Opera和Chrome实现&#x…...

JavaWeb12-线程通讯(线程等待和唤醒)
目录 1.方法介绍 1.1.wait()/wait(long timeout):让当前线程进入等待状态。 1.1.1.wait执行流程 1.1.2.wait结束等待的条件 1.1.3.wait() VS wait(long timeout) 1.1.4.为什么wait要放在Object中? --->PS:wait(0) 和 sleep(0) 的区…...

江苏专转本如何事半功倍的备考
专转本如何事半功倍的备考 一个人学习成绩的优劣取决于他的学习能力,学习能力包括三个要素:规范的学习行为;良好的学习习惯;有效的学习方法。有了规范的学习行为才能培养出良好的学习习惯,形成了良好的学习习惯就会形成…...

linux下安装mongoDB
一、下载mongoDB包 下载地址: https://www.mongodb.com/try/download/community 个人建议:如果是学习阶段,使用5以下版本更好些。 二、安装及配置 1、安装 # 1、解压 $ tar -zxvf mongodb-linux-x86_64-rhel70-4.4.19-rc1.tgz# 2、迁移目…...

掌握MySQL分库分表(七)广播表、绑定表实战,水平分库+分表实现及之后的查询和删除操作
文章目录什么是广播表广播表实战数据库配置表Java配置实体类配置文件测试广播表水平分库分表配置文件运行测试什么是绑定表?绑定表实战配置数据库配置Java实体类配置文件运行测试水平分库分表后的查询和删除操作查询操作什么是广播表 指所有的分片数据源中都存在的…...

企业为什么需要数据可视化报表
数据可视化报表是在商业环境、市场环境已经改变之后,发展出来为当前企业提供替代解决办法的重要方案。而且信息化、数字化时代,很多企业已经进行了初步的信息化建设,沉淀了大量业务数据,这些数据作为企业的资产,是需要…...

5个有效的华为(HUAWEI)手机数据恢复方法
5个有效的手机数据恢复方法 华为智能手机中的数据丢失比许多人认为的更为普遍。发生这种类型的丢失有多种不同的原因,因此数据恢复软件的重要性。您永远不知道您的智能手机何时会在这方面垮台;因此,预防总比哀叹好,这就是为什么众…...

【Java并发编程】线程安全(一)Synchronized原理
Synchronized底层实现 简单来说,Synchronized关键字的执行主体是线程对象,加锁是通过一个锁对象来完成的是,而锁对象底层关联了一个c源码的monitor的对象,monitor对象底层又对应了操作系统级别的互斥锁,同一时刻只有一…...
[apollo]vue3.x中apollo的使用
[apollo]vue3.x中apollo的使用通过客户端获取Apollo配置环境工具的安装获取Apollo配置相关代码错误提示Uncaught (in promise) Error: Apollo client with id default not found. Use provideApolloClient() if you are outside of a component setup通过开放接口获取Apollo配置…...
system()函数启用新进程占有原进程的文件描述符表的问题
我在A程序中占用了/dev/video0这个独占模式的设备文件,在A中用system函数启用了B程序,B程序的代码中并不包含对/dev/video0的访问,但是我发现B程序也占用了/dev/video0,并且我在A程序中关闭了/dev/video0后,A程序不再占…...

nignx(安装,正反代理,安装tomcat设置反向代理,ip透传)
1安装nginx 安装wget Yum install -y wget 下载(链接从官网找到右键获取) 以下过程root 安装gcc Yum -y install gcc c 安装pcre Yum install -y pcre pcre-devel Openssl Yum install -y openssl openssl-devel 安装zlib Yum install -y zlib zlib-devel 安装make Yum inst…...
sklearn模块常用内容解析笔记
文章目录 回归模型评价指标R2_score预备知识R2_score计算公式r2_score使用方法注意事项参考文献回归模型评价指标R2_score 回归模型的性能的评价指标主要有:RMSE(平方根误差)、MAE(平均绝对误差)、MSE(平均平方误差)、R2_score。但是当量纲不同时,RMSE、MAE、MSE难以衡量模…...

我的 System Verilog 学习记录(2)
引言 从本文开始,就开始系统学习 System Verilog ,不只是语法,还有结合 Questa Sim 的实际编程练习、Debug。 本文简单介绍 System Verilog 语言的用途以及学习的必要性。 前文链接: 我的 System Verilog 学习记录(…...
【调研报告】Monorepo 和 Multirepo 的风格对比及使用示例
带有权重的Monorepo和Multirepo对比 功能/特性MonorepoMultirepoMonorepo权重值Multirepo权重值代码管理管理多个代码库更加复杂管理单个代码库更加简单37依赖管理可以简化依赖管理依赖冲突可能会更加困难73构建和部署构建和部署更加容易构建和部署可能需要更多的配置82团队协…...

Retrofit源码分析
文章目录一、简介二、源码分析2.1Retrofit的本质流程2.2源码分析2.2.1 创建Retrofit实例步骤1步骤2步骤3步骤4步骤5总结2.2.2创建网络请求接口的实例外观模式 & 代理模式1.外观模式2. 代理模式步骤3步骤4总结2.2.3执行网络请求同步请求OkHttpCall.execute()1.发送请求过程2…...

Mybatis-Plus入门系列(20) -兼容多种数据库
有道无术,术尚可求,有术无道,止于术。 文章目录前言方案分析1. 分页2. XML自定义SQL案例演示1. 配置2. 简单分页查询3. 带方言的分页查询参考前言 在我们实际开发软件产品过程中,数据库的类型可能不是确定的,也有客户…...

JetPack板块—Android X解析
Android Jetpack简述 AndroidX 是Android团队用于在Jetpack中开发,测试,打包,发布和版本管理的开源项目。相比于原来的Android Support库,AndroidX 可以称得上是一次重大的升级改进。 和Support库一样,AndroidX与Android 操作系…...
C++学习笔记-数字
当我们使用数字时,通常我们使用原始数据类型,例如 int,short,long,float 和 double 等。数字数据类型,它们的可能值和取值范围在讨论 C 数据类型时已经解释了。 C 定义数字 我们已经在之前笔记的各种实例…...

Nginx——Nginx的基础原理
摘要 Nginx 是俄罗斯人编写的十分轻量级的 HTTP 服务器,是一个高性能的HTTP和反向代理服务器,同时也是一个 IMAP/POP3/SMTP 代理服务器。Nginx 是由俄罗斯人 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,它已经在该站点运行超过两年半了。…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...