C++学习第十一天——vector的模拟实现

✨                               生于火焰,落俗不可避免,但浪漫至死不渝       🌏 

📃个人主页:island1314

🔥个人专栏:C++学习

🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏  💞 💞 💞


目录

vector模拟实现完整代码:

1.vector成员变量

🍵构造函数

📘默认构造

📘拷贝构造

📘迭代器区间初始化

📘n个val构造

📘initializer_list构造

📘赋值运算符重载

2、有关容量和数据个数的函数

3、扩容reserve()

4、operate[]

5、析构函数

6、尾插push_back

7、迭代器

迭代器代码测试:

8、插入insert

9、删除erase

🍋课外知识点:

🍵结语



vector模拟实现完整代码

#pragma once#include <assert.h>
namespace qian {template<class T>class vector{public:typedef const T* const_iterator;typedef T* iterator;const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}iterator begin(){return _start;}iterator end(){return _finish;}//类模板的成员函数,迭代器区间初始化//函数模板  -- 目的支持任意容器迭代器区间初始化template <class InputIterator>vector(InputIterator first, InputIterator last){//reserve(last - first);while (first != last){push_back(*first);++first;}}//n个val构造vector(size_t n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象T(){reserve(n);while(n--){push_back(val);}}//n个val构造,第一个参数为int类型vector(int n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象T(){reserve(n);while(n--){push_back(val);}}//initializer_list构造vector(initializer_list<T> il){reserve(il.size());for (auto e : il){push_back(e);}}//默认构造vector():_start(nullptr), _finish(nullptr), _endOfStorage(nullptr){}// v2 (v1)vector(const vector<T>& v){reserve(v.capacity());for (auto e : v) push_back(e);}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}// v1 = v3vector<T>& operator = (vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}void reserve(size_t n) //开辟空间{if (n > capacity()){size_t oldsize = size(); //保存旧空间T* tmp = new T[n];if (_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 resize(size_t n, const T& value = T()){// 1、如果n小于当前的size,则数据个数缩小到nif (n <= size()){_finish = _start + n;return;}// 2、空间不够则增容if (n > capacity()) reserve(n);//3、将size扩大到niterator it = _finish;iterator _finish = _start + n;while (it != _finish){*it = value;++it;}}size_t capacity() const{return _end_of_storage - _start;}size_t size() const{return _finish - _start;}T& operator[](size_t i){assert(i < size());return _start[i];}const T& operator[](size_t i) const{assert(i < size());return _start[i];}void push_back(const T& x){if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity); //扩容}*_finish = x; //插入数据++_finish; //尾部指针后移//insert(end(), x);}void pop_back(const T& x){/*assert(size() > 0);--_finish;*/erase(--end());}iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){//防止迭代器因为后面的扩容失效,所以要提前记录pos位置size_t len = pos - _start;//size_t len = size();size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len; //判断扩容之后os位置,防止野指针出现使迭代器失效}iterator end = _finish - 1; //后移while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it != _finish) //从pos + 1开始往前移动{*(it - 1) = *it;++it;}--_finish;return pos;}private:iterator _start = nullptr; //相当于_aiterator _finish = nullptr; //_a+sizeiterator _end_of_storage = nullptr; //_a + capacity};void test_vector1(){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);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;for (auto e : v1){cout << e << " ";}cout << endl;//int* it = v1.begin();// 封装vector<int>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";++it;}cout << endl;//cout << typeid(it).name() << endl;}void test_vector2(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);/*for (auto e : v1){cout << e << " ";}cout << endl;*/v1.insert(v1.begin(), 0);for (auto e : v1){cout << e << " ";}cout << endl;cout << "删除第一个位置:";v1.erase(v1.begin());for (auto e : v1){cout << e << " ";}cout << endl;int x;cin >> x;// 没有x就不插入,有x的前面插入 vector<int>::iterator it = find(v1.begin(), v1.end(), x);if (it != v1.end()){// insert以后it这个实参会不会失效?//v1.insert(it, 1000); //有点问题it = v1.insert(it, 1000);// 建议失效后迭代器不要访问。除非赋值更新一下这个失效的迭代器cout << *it << endl;}for (auto e : v1){cout << e << " ";}cout << endl;}void test_vector3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (auto e : v1){cout << e << " ";}cout << endl;int x;cin >> x;vector<int>::iterator it = find(v1.begin(), v1.end(), x);if (it != v1.end()){it = v1.erase(it);if (it != v1.end())cout << *it << endl;}for (auto e : v1){cout << e << " ";}cout << endl;}void test_vector4() //删除{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (auto e : v1){cout << e << " ";}cout << endl;int x;cin >> x;vector<int>::iterator it = find(v1.begin(), v1.end(), x);if (it != v1.end()){//v1.erase(it); //挂掉it = v1.erase(it);if (it != v1.end()) //不加这句话删除最后一个元素会挂掉cout << *it << endl; //帮助我们访问循环内的错误}for (auto e : v1){cout << e << " ";}cout << endl;}void test_vector5(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int> v2(v1);for (auto e : v2){cout << e << " ";}cout << endl;vector<int> v3;v3.push_back(10);v3.push_back(20);v3.push_back(30);v1 = v3;for (auto e : v3){cout << e << " ";}cout << endl;}void test_vector6(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int> v2(v1.begin() + 1, v1.end());for (auto e : v2){cout << e << " ";}cout << endl;string s("hello");vector<int> v3(s.begin(), s.end());for (auto e : v3){cout << e << " ";}cout << endl;}void test_vector7(){// C++内置类型进行了升序,也有构造int i = 0;int j(1);int k = int();int x = int(2);vector<string> v1(10);vector<string> v2(10, "xxx");for (auto e : v1){cout << e << " ";}cout << endl;for (auto e : v2){cout << e << " ";}cout << endl;vector<int> v3(10,1); //若没有迭代器函数区间匹配,可以将就运行//vector <int> v3(10u, 1); //因为调用的是unsigned那个for (auto e : v3){cout << e << " ";}cout << endl;vector<int> v4(10, 1);for (auto e : v4){cout << e << " ";}cout << endl;}class A{public://单参数隐式类型转换A(int a1 = 0):_a1(a1), _a2(0){}A(int a1, int a2) //多参数隐式类型转换:_a1(a1), _a2(a2){}private:int _a1;int _a2;};void test_vector8() //删除{//多参数隐式类型转换//多参数隐式类型转换A aa1(1, 1);//A aa2 = (1, 1);A aa2 = { 1, 1 }; // 多参数隐式类型转换A aa9{ 2,2 }; //不要A aa3(1);A aa4 = 1;A aa5(1);A aa6 = { 1 }; //不要A aa7{ 1 }; //不要const A& aa8 = { 1,1 };auto il1 = { 1,2,3,4,5,6 };vector<A> v3 = {1, A(1),A(2,2),A{2,2},{1},{2,2} };}void test_vector9(){vector<string>v1;v1.push_back("111111111");v1.push_back("111111111");v1.push_back("111111111");v1.push_back("111111111");v1.push_back("111111111");for (auto e : v1){cout << e << " ";}cout << endl;}}

1.vector成员变量

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

假设vector中已经有6个数据,我们来看看具体图片方便对成员变量进行理解

#include<iostream>
using namespace std;

namespace qian
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;    //将T*typedef成iterator
    private:
        iterator _start = nullptr;    //这里给缺省值
        iterator _finish = nullptr;
        iterator _end_of_storage = nullptr;
    }
};

这里有两个需要注意的地方:

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

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


🍵构造函数

📘默认构造

vector():_start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
{}
//上下等价
//vector() = default; //强制编译器生成默认的

📘拷贝构造

// v2 (v1)
vector(const vector<T>& v)
{reserve(v.capacity());for (auto e : v) push_back(e);
}

代码测试:

void test_vector5()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int> v2(v1);for (auto e : v2){cout << e << " ";}cout << endl;
}

📘迭代器区间初始化

//类模板的成员函数,迭代器区间初始化
//函数模板  -- 目的支持任意容器迭代器区间初始化
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{//reserve(last - first);while (first != last){push_back(*first);++first;}
}

📘n个val构造

//n个val构造
vector(size_t n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象T()
{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);}
}

     注意:之所以用两个类似的是因为编译器在匹配函数时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类型,没有迭代器区间初始化的函数匹配。

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

代码测试:

void test_vector7()
{vector<string> v1(10);vector<string> v2(10, "xxx");for (auto e : v1){cout << e << " ";}cout << endl;for (auto e : v2){cout << e << " ";}cout << endl;vector<int> v3(10,1); //若没有迭代器函数区间匹配,可以将就运行//vector <int> v3(10u, 1); //因为调用的是unsigned那个for (auto e : v3){cout << e << " ";}cout << endl;vector<int> v4(10, 1);for (auto e : v4){cout << e << " ";}cout << endl;
}

📘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);}
}

代码测试:

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

📘赋值运算符重载

// v1 = v3
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);
}

代码测试:

void test_vector5()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int> v3;v3.push_back(10);v3.push_back(20);v3.push_back(30);v1 = v3;for (auto e : v1){cout << e << " ";}cout << endl;
}


2、有关容量和数据个数的函数

//容量
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 = size(); //保存旧空间T* tmp = new T[n];if (_start){//memcpy(tmp, _start, sizeof(T) * size()); //memcpy 进行的是浅拷贝for (size_t i = 0; i < oldsize; i++) //深拷贝,转移数据{tmp[i] = _start[i];}delete[] _start; //释放旧空间}_start = tmp;   //新空间的起点_finish = _start + oldsize;_end_of_storage = _start + n;}
}

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

值得注意的是:我们避免了使用memcpy的浅拷贝,使用的是深拷贝。

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

🥳🥳有关resize的函数

void resize(size_t n, const T& value = T())
{// 1、如果n小于当前的size,则数据个数缩小到nif (n <= size()){_finish = _start + n;return;}// 2、空间不够则增容if (n > capacity()) reserve(n);//3、将size扩大到niterator it = _finish;iterator _finish = _start + n;while (it != _finish){*it = value;++it;}
}

4、operate[]

这里获得的是vector里面存储的数据

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

5、析构函数

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

6、尾插push_back

void push_back(const T& x)
{if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2; //判断需要扩容空间reserve(newcapacity); //扩容}*_finish = x; //插入数据++_finish;//尾部指针后移
}

7、迭代器

//普通迭代器
iterator begin()
{return _start;
}iterator end()
{return _finish;
}
//提供给const对象使用的迭代器,指向的内容不可以被修改
const_iterator begin() const
{return _start;
}const_iterator end() const
{return _finish;
}

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

迭代器代码测试:

void test_vector1()
{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);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//迭代器遍历//int* it = v1.begin();// 封装vector<int>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";++it;}cout << endl;//cout << typeid(it).name() << endl;//for循环遍历,实质上就是通过迭代器来实现的for (auto e : v1){cout << e << " ";}cout << endl;
}


8、插入insert

iterator insert(iterator pos, const T& x)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){//防止迭代器因为后面的扩容失效,所以要提前记录pos位置size_t len = pos - _start;//size_t len = size();size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len; //判断扩容之后os位置,防止野指针出现使迭代器失效}iterator end = _finish - 1; //后移while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;
}

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

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

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

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

9、删除erase

iterator erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it != _finish) //从pos + 1开始往前移动{*(it - 1) = *it;++it;}--_finish;return pos;
}

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

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

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

插入删除代码测试

void test_vector2()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.insert(v1.begin(), 0);for (auto e : v1){cout << e << " ";}cout << endl;cout << "删除第一个位置:";v1.erase(v1.begin());for (auto e : v1){cout << e << " ";}cout << endl;int x;cin >> x;// 没有x就不插入,有x的前面插入 vector<int>::iterator it = find(v1.begin(), v1.end(), x);if (it != v1.end()){// insert以后it这个实参会不会失效?//v1.insert(it, 1000); //有点问题it = v1.insert(it, 1000);// 建议失效后迭代器不要访问。除非赋值更新一下这个失效的迭代器cout << *it << endl;}for (auto e : v1){cout << e << " ";}cout << endl;if (it != v1.end()){it = v1.erase(it);if (it != v1.end())cout << *it << endl;}    for (auto e : v1){cout << e << " ";}cout << endl;
}


🍋课外知识点:

💎1、vector底层是以当前类型的指针作为迭代器,对于指针而言,能够进行操作的方法都支持,如==,++,*,而>>运算符并没有重载。

💎2、在vs系列编译器中,debug模式下,关于std::vector::at 和 std::vector::operator[] :

debug模式  at() 和 operator[] 都是根据下标获取任意位置元素的,在debug模式下两者都会去做边界检查。当发生越界行为时,at 是抛异常operator[] 内部的assert会触发

💎3、vector的插入操作如果导致底层空间重新开辟,则迭代器就会失效。如果空间足够,不扩容时,迭代器不一定失效,比如push_back尾插,元素插入到空间末尾,在不扩容时不会对迭代器产生影响。

💎4、vector删除,若当前元素迭代器失效,后面元素会牵扯到移动数据,因此删除元素后面的迭代器也会失效。


🍵结语

以上就是C++STL标准库中vector的模拟实现了,在实现过程中,我们使用了动态内存分配来实现vector的大小动态调整,并通过指针来管理内存。我们还实现了一些常用的成员函数,如push_back、pop_back、at等,以及一些运算符重载,如[]、=等。

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

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

相关文章

DevExpress开发WPF应用实现对话框总结

说明&#xff1a; 完整代码Github​&#xff08;https://github.com/VinciYan/DXMessageBoxDemos.git&#xff09;DevExpree v23.2.4&#xff08;链接&#xff1a;https://pan.baidu.com/s/1eGWwCKAr8lJ_PBWZ_R6SkQ?pwd9jwc 提取码&#xff1a;9jwc&#xff09;使用Visual St…

基于Spring前后端分离版本的论坛系统-自动化测试

目录 前言 一、测试环境 二、环境部署 三、测试用例 四、执行测试 4.1、公共类设计 创建浏览器驱动对象 测试套件 释放驱动类 4.2、功能测试 注册页面 登录页面 版块 帖子 用户个人中心页 站内信 4.3、界面测试 注册页面 登录页面 版块 帖子 用户个人中心页…

Redis实战篇3:优惠券秒杀

说明 该实战篇基于某马的Redis课程中的《某马点评项目》。非常适合有相关经验、缺少企业级解决方案&#xff0c;或者想要复习的人观看&#xff0c;全篇都会一步一步的推导其为什么要这么做&#xff0c;分析其优缺点&#xff0c;达到能够应用的地步。 本实战篇中心思想就是把项目…

Mariadb操作命令指南

MariaDB简介 ​ 以下内容仅是站长或网友个人学习笔记、总结和研究收藏。不保证正确性&#xff0c;因使用而带来的风险与本站无关&#xff01; 数据库应用程序与主应用程序分开存在&#xff0c;并存储数据集合。 每个数据库都使用一个或多个API来创建&#xff0c;访问&#xf…

分立元件实现稳压

电路原理图 优点&#xff1a;电压精度高&#xff0c;可以调整输出电压 缺点&#xff1a;压差大时效率较低&#xff0c;发热严重。 参考连接 TL431-高效5V精密稳压器-电路知识干货 (qq.com)https://mp.weixin.qq.com/s?__bizMzkxNzIxNTc5OQ&mid2247484878&idx1&…

操作系统教材第6版——个人笔记1

第一章 计算机操作系统概述 操作系统是计算机系统中最重要的系统软件&#xff0c;它统一管理计算机系统的硬件资源与信息资源&#xff0c;控制与调度上层软件的执行并为其提供易于使用的接口。从资源管理、程序控制、操作控制、人机交互、程序接口、系统结构6个角度深入观察操…

Github 如何配置 PNPM 的 CI 环境

最近出于兴趣在写一个前端框架 echox&#xff0c;然后在 Github 上给它配置了最简单的 CI 环境&#xff0c;这里简单记录一下。 特殊目录 首先需要在项目根目录里面创建 Github 仓库中的一个特殊目录&#xff1a;.github/workflows&#xff0c;用于存放 Github Actions 的工作…

269 基于matlab的四连杆机构动力学参数计算

基于matlab的四连杆机构动力学参数计算。将抽油机简化为4连杆机构&#xff0c;仿真出悬点的位移、速度、加速度、扭矩因数、游梁转角等参数&#xff0c;并绘出图形。程序已调通&#xff0c;可直接运行。 269机构动力学参数计算 位移、速度、加速度 - 小红书 (xiaohongshu.com)

段码屏|液晶显示模块|超低功耗LCD驱动芯片

1 简介 PC164S32 是一款支持 128 点 (32 4)显示 的多功能 LCD 控制器芯片&#xff0c;内部存储器RAM数据直接映射到 LCD 显示。可软件配置特性使其适用于包括 LCD 模块和显示子系统在内的多种 LCD 应用。主控制器与 PC164S32接口仅需3 或 4 条线。内置的省电模式极大的降低了功…

我给线程池管理框架hippo4j找bug

1 虚拟机参数不生效 hippo4j的docker启动脚本位于 docker/docker-startup.sh 。从下图可以看到 JAVA_OPT放在了jar包名 hippo4j-server.jar之后&#xff0c;而只有项目参数才放在jar包名之后。 实际上这里JAVA_OPT中包含虚拟机参数&#xff0c;而虚拟机参数要放在jar包名之前…

使用 CNN 训练自己的数据集

CNN&#xff08;练习数据集&#xff09; 1.导包&#xff1a;2.导入数据集&#xff1a;3. 使用image_dataset_from_directory()将数据加载tf.data.Dataset中&#xff1a;4. 查看数据集中的一部分图像&#xff0c;以及它们对应的标签&#xff1a;5.迭代数据集 train_ds&#xff0…

【漏洞复现】DT-高清车牌识别摄像机 任意文件读取漏洞

0x01 产品简介 DT-高清 车牌识别摄像机是一款先进的安防设备&#xff0c;采用高清图像传感器和先进的识别算法&#xff0c;能够精准、快速地识别车牌信息。其高清晰该摄像机结合了智能识别技术&#xff0c;支持实时监宴图像质量确保在各种光照和天气条件下都能准确捕捉车牌信息…

【面试八股总结】MySQL事务:事务特性、事务并行、事务的隔离级别

参考资料&#xff1a;小林coding 一、事务的特性ACID 原子性&#xff08;Atomicity&#xff09; 一个事务是一个不可分割的工作单位&#xff0c;事务中的所有操作&#xff0c;要么全部完成&#xff0c;要么全部不完成&#xff0c;不会结束在中间某个环节。原子性是通过 undo …

C#根据数据量自动排版标签的样例

这是一个C#根据数据量自动排版标签的样例 using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Drawing; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using HslCommuni…

代码随想录算法训练营第四十五天 | 1049. 最后一块石头的重量 II、494. 目标和、474.一和零

1049. 最后一块石头的重量 II 视频讲解&#xff1a; 动态规划之背包问题&#xff0c;这个背包最多能装多少&#xff1f;LeetCode&#xff1a;1049.最后一块石头的重量II_哔哩哔哩_bilibili 代码随想录 解题思路 直接将这一些石头&#xff0c;分为两堆&#xff0c;让他们尽可能…

C语言 | Leetcode C语言题解之第120题三角形最小路径和

题目&#xff1a; 题解&#xff1a; int minimumTotal(int** triangle, int triangleSize, int* triangleColSize) {int f[triangleSize];memset(f, 0, sizeof(f));f[0] triangle[0][0];for (int i 1; i < triangleSize; i) {f[i] f[i - 1] triangle[i][i];for (int j …

【excel】设置二级联动菜单

文章目录 【需求】在一级菜单选定后&#xff0c;二级菜单联动显示一级菜单下的可选项【步骤】step1 制作辅助列1.列转行2.在辅助列中匹配班级成员 之前做完了 【excel】设置可变下拉菜单&#xff08;一级联动下拉菜单&#xff09;&#xff0c;开始做二级联动菜单。 【需求】在…

python实现——综合类型数据挖掘任务(无监督的分类任务)

综合类型数据挖掘任务 航空公司客户价值分析。航空公司客户价值分析。航空公司客户价值分析。航空公司已积累了大量的会员档案信息和其乘坐航班记录&#xff08;air_data.csv&#xff09;&#xff0c;以2014年3月31日为结束时间抽取两年内有乘机记录的所有客户的详细数据。利用…

万界星空科技MES系统功能介绍

制造执行系统或MES 是一个全面的动态软件系统&#xff0c;用于监视、跟踪、记录和控制从原材料到成品的制造过程。MES在企业资源规划(ERP) 和过程控制系统之间提供了一个功能层&#xff0c;为决策者提供了提高车间效率和优化生产所需的数据。 万界星空科技MES 系统基础功能&am…

【全开源】Java短剧系统微信小程序+H5+微信公众号+APP 源码

打造属于你的精彩短视频平台 一、引言&#xff1a;为何选择短剧系统小程序&#xff1f; 在当今数字化时代&#xff0c;短视频已经成为人们日常生活中不可或缺的一部分。而短剧系统小程序源码&#xff0c;作为构建短视频平台的强大工具&#xff0c;为广大开发者提供了快速搭建…