【C++】Vector的简易模拟与探索

💞💞 前言

hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹
在这里插入图片描述

💥个人主页:大耳朵土土垚的博客
💥 所属专栏:C++入门至进阶
这里将会不定期更新有关C++的内容,希望大家多多点赞关注收藏💖💖

目录

  • 💞💞 前言
  • vector模拟实现完整代码
  • 1.vector成员变量
  • 2.尾插push_back()
  • 3.扩容reserve()
  • 4.operate[]
  • 5.析构函数
    • ✨测试代码
  • 6.迭代器
    • const迭代器
    • ✨迭代器测试代码
  • 7.插入insert()
  • 8.删除erase()
    • ✨插入删除测试代码
  • 9.构造函数
    • ✨拷贝构造
    • 拷贝构造测试代码
    • ✨默认构造
    • ✨迭代器区间初始化
    • ✨n个val构造
    • n个val构造测试代码
    • ✨initializer_list构造
    • initializer_list构造测试代码
  • 10.赋值运算符重载
  • 11.reserve()扩容存在的问题
    • ✨测试代码
  • 结语

vector模拟实现完整代码

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
#define _CRT_SECURE_NO_WARNINGS 1
namespace tutu
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;//迭代器iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}//构造函数//拷贝构造,深拷贝vector(const vector<T>& v){//提前预留空间reserve(v.capacity());for (auto i : v){push_back(i);}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}//赋值运算符重载vector<T>& operator=(vector<T> v){swap(v);return *this;}//默认构造vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}//迭代器区间初始化//函数模板template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}//n个val构造vector(size_t n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象{reserve(n);while (n--){push_back(val);}}//n个val构造重载,第一个参数为int类型vector(int n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象{reserve(n);while (n--){push_back(val);}}//initializer_list构造vector(initializer_list<T> il){reserve(il.size());for (auto i : il){push_back(i);}}//析构函数~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}//容量size_t capacity() const{return _end_of_storage - _start;}//数据个数size_t size()	const{return _finish - _start;}//扩容void reserve(size_t n){if (n > capacity()){size_t oldsize = _finish - _start;T* tmp = new T[n];//memcpy(tmp, _start, oldsize * sizeof(T));	//拷贝数据,浅拷贝对于string类等不适用if (_start)//如果_start为空就不需要拷贝数据{for (size_t i = 0; i < oldsize; i++){tmp[i] = _start[i];//使用赋值来实现深拷贝}}delete[] _start;	//释放旧的空间_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}}//尾插void push_back(const T& x){/*if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();reserve(newcapacity);}*_finish = x;++_finish;*/insert(end(), x);}T& operator[](size_t pos){assert(pos < size());return _start[pos];}//const对象使用const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}//尾删void pop_back(){if (_finish != _start)//判断是否为空{--_finish;}}//插入iterator insert(iterator pos, const T& x){//防止迭代器因为后面的扩容失效,所以要提前记录pos位置size_t pos_size = pos - _start;//断言防止越界assert(pos_size <= size());assert(pos_size >= 0);//看是否扩容if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();reserve(newcapacity);}//如果扩容,pos可能会失效,所以要更新pospos = begin() + pos_size;//往后挪动数据iterator cur = _finish;while (cur != pos){*cur = *(cur - 1);cur--;}//插入数据*pos = x;_finish++;return pos;}//删除iterator erase(iterator pos){size_t pos_size = pos - _start;//断言防止越界assert(pos >= _start);assert(pos < _finish);//往前挪动数据iterator cur = pos;while (cur != _finish - 1){*cur = *(cur + 1);cur++;}_finish--;//更新pospos = _start + pos_size;return pos;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};//测试代码尾插和[]void vectortest1(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(4);v1.push_back(4);for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;}//迭代器测试void vectortest2(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);int* it = v1.begin();//指定类域 //int* it  = v1.begin();//也可以while (it != v1.end()){cout << *it << " ";it++;}}//范围for测试void vectortest3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto i : v1){cout << i << " ";}}//插入删除数据测试void vectortest4(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.insert(v1.begin(), 0);v1.erase(v1.begin());v1.erase(v1.end() - 1);for (auto i : v1){cout << i << " ";}}//n个val测试代码1void vectortest5(){vector<string> s1(10);//使用缺省值vector<string> s2(10, "hello");for (auto i : s1){cout << i << " ";}cout << endl;for (auto i : s2){cout << i << " ";}}//n个val测试代码2void vectortest6(){vector<int> v1(4, 2);for (auto i : v1){cout << i << " ";}}//initializer_list构造测试void vectortest7(){vector<int> v1({ 1,2,3,4,5 });vector<int> v2 = { 6,7,8,9,10 };for (auto i : v1){cout << i << " ";}cout << endl;for (auto i : v2){cout << i << " ";}}//扩容测试代码void vectortest8(){vector<string> s1;s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");for (auto i : s1){cout << i << " ";}}
}

1.vector成员变量

在查看STL库里面vector的实现时,我们发现它是一个类模板并且定义了三个成员变量,分别是iterator startiterator finishiterator end_of_storage用来标记开始,结束,以及总容量,对于vector来说其迭代器iterator就是T*,例如我们之前学习过的顺序表插入的是int类型的数据,所以对存放int类型的vector来说T*就是int*

如下图所示:
假设vector里已经插入了6个数据
在这里插入图片描述

#include<iostream>
using namespace std;namespace tutu
{template<class T>class vector{public:typedef T* iterator;	//将T*typedef成iteratorprivate:iterator _start = nullptr;	//这里给缺省值iterator _finish = nullptr;iterator _end_of_storage = nullptr;}
};

因为还没有写构造函数,所以成员变量那里先给缺省值,方便使用

这里将vector的实现都放在一个头文件下,放置多个文件可能会出现链接错误;并设置自己的命名空间tutu

2.尾插push_back()

void push_back(const T& x)
{//判断容量是否够用if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();//扩容reserve(newcapacity);}//插入数据*_finish = x;_finish++;
}

插入数据首先都应该判断一下容量是否够用,不够用就需要扩容,这里使用reserve()函数扩容,该函数将在后面实现,此外插入数据后_finish要往后偏移一位

🥳🥳有关容量和数据个数的函数:

//容量
size_t capacity() const
{return _end_of_storage - _start;
}//数据个数
size_t size()	const
{return _finish - _start;
}

3.扩容reserve()

void reserve(size_t n)
{if (n > capacity()){size_t oldsize = _finish - _start;	//记录大小T* tmp = new T[n];memcpy(tmp, _start, oldsize*sizeof(T));	//拷贝数据delete[] _start;	//释放旧的空间_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}
}

扩容时,因为我们使用的实现vector类的成员变量是指针(或者说迭代器),所以改变空间后不仅仅_start改变,_finish指向的空间会被销毁,所以这时候如果再使用扩容后的_finish-_start来找到容量size来确定现在_finish指向的空间肯定是不对的,所以我们要提前记录好oldsize

这里拷贝数据使用的是memcpy,一个字节一个字节拷贝

4.operate[]

T& operator[](size_t pos)
{assert(pos < size());	//断言return _start[pos];
}

这里返回的是T的引用,也就是vector里面存储的数据

//const对象使用
const T& operator[](size_t pos) const
{assert(pos < size());return _start[pos];
}

5.析构函数

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

✨测试代码

void vectortest1()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;
}

结果如下:
在这里插入图片描述

可以看到尾插成功,并且可以使用[]来访问vector v1里面的元素

6.迭代器

//迭代器
iterator begin()
{return _start;
}iterator end()
{return _finish;
}

在最开始vector成员变量那里我们将T*typedef成iterator,所以对于vector类来说其迭代器实质上就是T*,是一个指针;但要注意不是所有的迭代器都是指针,例如list的迭代器就不是,我们后续再学习

const迭代器

提供给const对象使用的迭代器,指向的内容不可以被修改

const_iterator begin() const
{return _start;
}const_iterator end() const
{return _finish;
}

✨迭代器测试代码

使用迭代器来遍历数据

//迭代器测试
void vectortest2()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);vector<int>::iterator it = v1.begin();//指定类域 //T* it  = v1.begin();//也可以while (it != v1.end()){cout << *it << " ";it++;}
}

结果如下:
在这里插入图片描述

因为我们这里的迭代器实质上就是T*,所以vector<int>::iterator it = v1.begin();也可以写成这样:int* it = v1.begin();,但是最好还是使用第一个,因为这个是在所有的地方通用的,屏蔽了底层实现,体现了C++的封装的思想

此外范围for其实质上就是通过迭代器来实现的,所以我们写完了迭代器就可以使用范围for来遍历数据了,代码如下:

//范围for
void vectortest3()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto i : v1){cout << i << " ";}
}

7.插入insert()

//插入
iterator insert(iterator pos,const T& x)
{//防止迭代器因为后面的扩容失效,所以要提前记录pos位置size_t pos_size = pos - _start;//断言防止越界assert(pos_size <= size());assert(pos_size >= 0);//看是否扩容if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();reserve(newcapacity);}//如果扩容,pos可能会失效,所以要更新pospos = begin() + pos_size;//往后挪动数据iterator cur = _finish;while (cur != pos){*cur = *(cur - 1);cur--;}//插入数据*pos = x;_finish++;return pos;//返回更新后的迭代器
}

这里要注意迭代器因为扩容导致pos失效的问题(野指针),所以要提前规避,记录好pos相对位置,然后再即时更新pos迭代器,否则就会出现随机值;

此外,insert的参数pos是对实参的拷贝,形参的改变不会影响实参,所以外部的实参也会失效,但是我们也不能通过引用传参,因为其迭代器返回的是临时拷贝具有常性不能通过引用传参,所以这里我们就可以通过控制insert函数的返回值来解决,我们会返回更新后的迭代器,这样就可以访问该位置了

🥳🥳有了插入函数之后尾插push_back()就可以使用insert()来实现啦,代码如下:

//尾插
void push_back(const T& x)
{insert(end(), x);
}

8.删除erase()

//删除
iterator erase(iterator pos)
{size_t pos_size = pos - _start;//断言防止越界assert(pos >= _start);assert(pos < _finish);//往前挪动数据iterator cur = pos;while (cur != _finish - 1){*cur = *(cur + 1);cur++;}_finish--;//更新pospos = _start + pos_size;return pos;
}

erase()之后迭代器失效问题

  • 有可能删除之后缩容
  • 删除最后一个位置会导致越界访问

所以我们认为删除操作之后迭代器也会失效,和插入函数一样通过返回迭代器来更新迭代器使用才行

✨插入删除测试代码

//插入删除数据
void vectortest4()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.insert(v1.begin(), 0);v1.erase(v1.begin());v1.erase(v1.end()-1);for (auto i : v1){cout << i << " ";}
}

结果如下:
在这里插入图片描述

9.构造函数

✨拷贝构造

//拷贝构造,深拷贝
vector(const vector<T>& v)
{//提前预留空间reserve(v.capacity());for (auto i : v){push_back(i);}
}

拷贝构造测试代码

void vectortest5()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);vector<int> v2(v1);//用v1拷贝构造v2for (auto i : v2){cout << i << " ";}
}

结果如下:
在这里插入图片描述

✨默认构造

//默认构造
vector():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr)
{}

✨迭代器区间初始化

//迭代器区间初始化
//函数模板
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);++first;}}

这里使用了函数模板用来匹配不同类型的迭代器,因为vector可以存储不同类型的数据,相应的迭代器也会有所不同,所以使用函数模板

✨n个val构造

//n个val构造
vector(size_t n, const T& val=T())//缺省值不能给0,因为T可能是string,所以给匿名对象
{reserve(n);while (n--){push_back(val);}
}

注意这里给的缺省参数是匿名对象T(),而不是0,因为vector除了能存储int类型外还可以存储其他类型的数据比如string等

n个val构造测试代码

void vectortest5()
{vector<string> s1(10);//使用缺省值vector<string> s2(10, "hello");for (auto i : s1){cout << i << " ";}cout << endl;for (auto i : s2){cout << i << " ";}
}

结果如下:
在这里插入图片描述

上述代码s1使用的是缺省值匿名对象string()也就是’\0’,所以什么都没打印,第一行是空的,第二行打印s2的10个"hello"

但是当我们使用下面的代码测试的时候就会发现:

//n个val测试代码
void vectortest6()
{vector<int> v1(4, 2);for (auto i : v1){cout << i << " ";}
}

运行后:
在这里插入图片描述

出现了非法的间接寻址,并且报错在vector(InputIterator first, InputIterator last)迭代器区间初始化这里

这是因为编译器在匹配函数时vector<int> v1(4, 2);4和2都是int类型恰好和vector(InputIterator first, InputIterator last)这两个函数模板的参数匹配上了,而我们写的n个val初始化vector(size_t n, const T& val=T())第一个参数类型是size_t,第二个才可以隐式类型转换为int类型,没有迭代器区间初始化的函数匹配

所以编译器会选择使用迭代器区间来初始化v2,但是迭代器区间初始化函数里面写了解引用,对于int类型来说是行不通的,所以出现了错误

这时我们只需要在初始化v2时将第一个参数给为unsigned int就行:vector<int> v1(4u, 2);
或者可以在重载一个n个val构造的函数,第一个参数给为int类型:

//n个val构造重载,第一个参数为int类型
vector(int n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象
{reserve(n);while (n--){push_back(val);}
}

这样上述代码的结果就如下:
在这里插入图片描述

✨initializer_list构造

initializer_list是C++新增的一个类型,方便初始化,支持将花括号括起来的值给initializer_list,initializer_list对象里面有两个指针,指向花括号里面值开始和结尾的下一个,并支持迭代器,所以可以使用范围for来遍历,当然这个要编译器支持将花括号传给它

//initializer_list构造
vector(initializer_list<T> il)
{reserve(il.size());//size表示数据个数for (auto i : il){push_back(i);}
}

initializer_list构造测试代码

C++11引入

//initializer_list构造测试
void vectortest7()
{隐式类型转换vector<int> v1({ 1,2,3,4,5 });	vector<int> v2={ 6,7,8,9,10 };	for (auto i : v1){cout << i << " ";}cout << endl;for (auto i : v2){cout << i << " ";}
}

结果如下:
在这里插入图片描述

10.赋值运算符重载

//赋值运算符重载
vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}

这里使用传值传参,是实参的拷贝,所以我们将它与被赋值的对象交换后返回即可完成赋值,并且交换后形参生命周期结束就会自动调用析构函数释放原来的空间

🥳🥳swap函数

void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}

11.reserve()扩容存在的问题

✨测试代码

//扩容测试代码
void vectortest8()
{vector<string> s1;s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");s1.push_back("1111111111111");for (auto i : s1){cout << i << " ";}
}

结果如下:
在这里插入图片描述

可以看到程序异常退出,这是因为我们在使用reserve()扩容时,使用的是 memcpy(tmp, _start, oldsize*sizeof(T)); 来拷贝数据,如果数据是int类型不会有什么问题,但如果是string类,memcpy进行的是一个字节一个字节拷贝,是浅拷贝,释放原来的空间后,就会存在野指针,访问已经释放的空间出现错误,所以reserve实现应该如下:

//扩容
void reserve(size_t n)
{if (n > capacity()){size_t oldsize = _finish - _start;T* tmp = new T[n];//memcpy(tmp, _start, oldsize * sizeof(T));	//拷贝数据,浅拷贝对于string类等不适用if (_start)//如果_start为空就不需要拷贝数据{for (size_t i = 0; i < oldsize; i++){tmp[i] = _start[i];//使用赋值来实现深拷贝}}delete[] _start;	//释放旧的空间_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}
}

上述代码拷贝使用赋值,如果是类类型会调用赋值运算符重载实现你想要的拷贝,这样上述测试代码就可以测试成功啦🥳🥳

结果如下:

在这里插入图片描述

结语

以上就是C++STL标准库中vector的模拟实现了,在实现过程中,我们使用了动态内存分配来实现vector的大小动态调整,并通过指针来管理内存。我们还实现了一些常用的成员函数,如push_back、pop_back、at等,以及一些运算符重载,如[]、=等。
通过实现这个简单的vector类,我们不仅加深了对vector容器的理解,还学习了一些C++的底层原理和技巧。同时我们也遇见并解决了一些问题比如迭代器失效,深浅拷贝…以上就是今天所有的内容啦~ 完结撒花 ~🥳🎉🎉

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

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

相关文章

模型 FABE(特性 优势 好处 证据)法则

说明&#xff1a;系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。特性、优势、好处、证据&#xff0c;一气呵成。 1 FABE法则的应用 1.1 FABE法则营销商用跑步机 一家高端健身器材公司的销售代表正在向一家新开的健身房推销他们的商用跑步机。以下…

Microsoft Dynamics 365 Business Central 讲解VAT RATE CHANGE TOOL(增值税税率更改工具)

学习目标&#xff1a; 如果使用VAT RATE CHANGE TOOL&#xff08;增值税税率更改工具&#xff09; 过程演示&#xff1a; 1.创建新的VAT产品过账组 2.创建新的总账科目以过账采购、销售和逆向征收增值税。 3.给新的VAT产品过账设置过账设置 4.创建一个新的一般产品过账组 5…

CUDA学习(2)

什么是CUDA CUDA&#xff08;Compute Unified Device Architecture&#xff09;&#xff0c;统一计算设备架构&#xff0c;英伟达推出的基于其GPU的通用高性能计算平台和编程模型。 借助CUDA&#xff0c;开发者可以充分利用英伟达GPU的强大计算能力加速各种计算任务。 软件生…

手写HTML字符串解析成对应的 AST语法树

先看效果 展示如下&#xff1a; HTML模版 转成ast语法树后 在学习之前&#xff0c;我们需要了解这么一个问题&#xff0c;为什么要将HTML字符串解析成对应的 AST语法树。 为什么&#xff1f; 语法分析&#xff1a;HTML字符串是一种标记语言&#xff0c;其中包含了大量的标签…

chap5 CNN

卷积神经网络&#xff08;CNN&#xff09; 问题描述&#xff1a; 利用卷积神经网络&#xff0c;实现对MNIST数据集的分类问题 数据集&#xff1a; MNIST数据集包括60000张训练图片和10000张测试图片。图片样本的数量已经足够训练一个很复杂的模型&#xff08;例如 CNN的深层…

gcc 内建函数示例 __builtin_return_address

1,理论未动&#xff0c;示例先行 hello_gcc_callstack.c #include <stdio.h>void do_backtrace() {void *pc0 __builtin_return_address(0);void *pc1 __builtin_return_address(1);void *pc2 __builtin_return_address(2);void *pc3 __builtin_return_address(3);…

低边驱动与高边驱动

一.高边驱动和低边驱动 低边驱动(LSD): 在电路的接地端加了一个可控开关&#xff0c;低边驱动就是通过闭合地线来控制这个开关的开关。容易实现&#xff08;电路也比较简单&#xff0c;一般由MOS管加几个电阻、电容&#xff09;、适用电路简化和成本控制的情况。 高边驱动&am…

JVM哪些区域可能出现内存溢出,哪些地方需要GC?

GC顾名思义也就是垃圾回收&#xff0c;有人的地方就有江湖&#xff0c;那有数据的地方也理应有垃圾回收&#xff0c;所以思考一下&#xff0c;沿着之前提到过的JVM内存分区&#xff0c;堆&#xff0c;栈&#xff0c;程序计数器&#xff0c;方法区 堆、栈、方法区…

一键安装 HaloDB 之 Ansible for Halo

↑ 关注“少安事务所”公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ 前倾回顾 前面介绍了“光环”数据库的基本情况和安装办法。 哈喽&#xff0c;国产数据库&#xff01;Halo DB! 三步走&#xff0c;Halo DB 安装指引 以及 HaloDB 的 Oracle 和 MySQL 兼容模式: …

ChatGPT-4o 有何特别之处?

文章目录 多模态输入&#xff0c;多模态输出之前的模型和现在模型对比 大家已经知道&#xff0c;OpenAI 在 GPT-4 发布一年多后终于推出了一个新模型。它仍然是 GPT-4 的一个变体&#xff0c;但具有前所未见的多模态功能。 有趣的是&#xff0c;它包括实时视频处理等强大功能&…

Mac安装第三方软件的命令安装方式

场景&#xff1a; 打开终端命令行&#xff0c;sudo xattr -rd com.apple.quarantine&#xff0c;注意最后quarantine 后面加一个空格&#xff01;然后打开Finder&#xff08;访达&#xff09;&#xff0c;点击左侧的 应用程序&#xff0c;找到相关应用&#xff0c;拖进终端qua…

六一见!|Post Microsoft Build and AI Day 上海开发者日

编辑/排版&#xff1a;Alan Wang 大小朋友明天见&#xff01; 6月1日&#xff0c;Microsoft Azure & Microsoft Reactor 面向大小朋友特别推出六一特辑&#xff0c;「Post Microsoft Build and AI Day 上海开发者日」 探讨 Microsoft Build 2024 带来的最新发布&#xff0…

KT6368A双模蓝牙芯片上电到正常发送AT指令或指令复位需要多久

一、简介 KT6368A芯片上电到正常发送AT指令&#xff0c;或者开启蓝牙广播被搜索到&#xff0c;或者指令复位需要多久等等系列问题总结 详细描述 其实这些问题归结到一起&#xff0c;就还是一个问题&#xff0c;芯片上电需要多久的时间 在另外一份文档里面&#xff0c;是有描…

热门新游 2024 植物大战僵尸杂交版 Mac 版本下载安装详细教程

最近植物大战僵尸杂交版可谓是非常的火&#xff0c;好多主播都在播这款游戏&#xff0c;我一个 Mac 党也想玩&#xff0c;可奈何该游戏目前只有 PC 版本&#xff0c;经过一番折腾终于在我的 Mac 上安装上了该游戏&#xff0c;分享给大家 其实安装过程也很简单&#xff0c;只需…

C++ | Leetcode C++题解之第119题杨辉三角II

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> getRow(int rowIndex) {vector<int> row(rowIndex 1);row[0] 1;for (int i 1; i < rowIndex; i) {row[i] 1LL * row[i - 1] * (rowIndex - i 1) / i;}return row;} };

现在的时代,您必会的“调教”AI技巧。

人工智能大行其道&#xff0c;如何借势&#xff1f;始于问询。要得要得预期&#xff0c;精于“提问技巧”&#xff01; (笔记模板由python脚本于2024年05月30日 18:37:27创建&#xff0c;本篇笔记适合有独立编程基础的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#…

通过定时器和脉冲控制LED

一、定时器 &#xff08;一&#xff09;定时器简介 STM32定时器是STM32微控制器中的重要块&#xff0c;用于生成精确的时间基准。它可以用于测量时间间隔、产生脉冲、实现定时中断等功能。通过配置寄存器&#xff0c;用户可以灵活地控制定时器的工作模式和参数&#xff0c;实现…

Linux自动挂载服务autofs讲解

1.产生原因 2.配置文件讲解 总结&#xff1a;配置客户端&#xff0c;先构思好要挂载的目录如&#xff1a;/abc/cb 然后在autofs.master中编辑&#xff1a; /abc&#xff08;要挂载的主目录&#xff09; /etc/qwe&#xff08;在这个文件里去找要挂载的副目录&#xff0c;这个名…

Linux虚拟机根目录磁盘扩容

一、VMWare虚拟机扩展磁盘空间 在vmware软件中&#xff0c;选择对应的虚拟机&#xff0c;点击“硬盘”。【需要先关机再操作】 扩展 更改磁盘大小&#xff0c;点击“扩展”&#xff0c;然后一路“确定”。扩展到45G 二、启动虚拟机并扩展磁盘空间 查看磁盘使用情况 df -Th …

2024最新群智能优化算法:大甘蔗鼠算法(Greater Cane Rat Algorithm,GCRA)求解23个函数,提供MATLAB代码

一、大甘蔗鼠算法 大甘蔗鼠算法&#xff08;Greater Cane Rat Algorithm&#xff0c;GCRA&#xff09;由Jeffrey O. Agushaka等人于2024年提出&#xff0c;该算法模拟大甘蔗鼠的智能觅食行为。 参考文献 [1]Agushaka J O, Ezugwu A E, Saha A K, et al. Greater Cane Rat Alg…