当前位置: 首页 > news >正文

【STL】 vector的底层实现

1.vector的模拟代码完整实现(后面会拆分开一个一个细讲)

#pragma once
#include<assert.h>// 抓重点namespace bit
{/*template<class T>class vector{public:typedef T* iterator;private:T* _a;size_t _size;size_t _capacity;};*/template<class T>class vector{public:typedef T* iterator;typedef const T* const_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){while (first != last){push_back(*first);++first;}}vector(size_t n, const T& val = T()) //创建一个包含 n 个元素的向量,并且每个元素都被初始化为 val 的值。//如果没有提供 val 参数,则默认使用 T() 构造出的默认值。{reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}vector(initializer_list<T> il)//vector(initializer_list<T> il):这是 vector 类的构造函数。它允许使用花括号 {} 括起来的一组元素来初始化 vector 对象。{reserve(il.size());for (auto e : il){push_back(e);}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}// 强制编译器生成默认的vector() = default;// v2(v1)vector(const vector<T>& v){reserve(v.capacity());for (auto e : v){push_back(e);}}// 16:05继续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){//memcpy(tmp, _start, sizeof(T) * old_size);for (size_t i = 0; i < oldsize; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}}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(){assert(size() > 0);--_finish;}iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}// 迭代器// 勿在浮沙筑高台void erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it != _finish){*(it - 1) = *it;++it;}--_finish;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};

2.vector的成员变量

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

3.vector中的部分成员变量

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}iterator begin(){return _start;}iterator end(){return _finish;}

4.vector中的构造函数

        1.默认构造

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

        2.拷贝构造

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

        3.迭代器区间初始化

        

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

        4.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);}
}

5.对于构造函数的测试

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

6.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);}
}

6.1 initializer_list构造的测试代码

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 << " ";}
}

7.赋值运算符的重载

// v1 = v3
vector<T>& operator = (vector<T> v)
{swap(v);return *this;
}

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

5.vector类中的容量操作

1.size 与 capacity

int main(){cout << "指定⼤⼩为10时:\n";vector<int> v(10, 1);cout << v.size() << endl;cout << v.capacity() << endl;vector<int> v1;v1.push_back(1);v1.push_back(1);v1.push_back(1);v1.push_back(1);cout << "插⼊四个数据时:\n";cout << v1.size() << endl;cout << v1.capacity() << endl;cout << "插⼊五个数据时:\n";v1.push_back(1);cout << v1.size() << endl;cout << v1.capacity() << endl;return 0;}
输出结果:
指定⼤⼩为10时:
1010
插⼊四个数据时:
44
插⼊五个数据时:
58

capacity的代码在g++ vs 和 clang下分别允许会发现,vs下capacity是按1.5倍增⻓,clang和g++是按2倍增⻓。这个 问题经常会考察,不要固化的认为,vector增容都是2倍,具体增⻓多少是根据具体的需求定义的。vs是PJ版本 STL,g++是SGI版本STL

2.resize

resize在开空间的同时还会进⾏初始化,影响size 使⽤resize()函数可以改变调⽤对象的size和capacity⼤⼩,如果指定的⼤⼩⼩于size时相当于删除数据,当指定⼤⼩ ⼤于size时则作⽤为扩容+初始化(对于int默认初始化为0)

int main(){vector<int> v(10, 1);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 1 1 1 1 1 1 1 1 1 
v.resize(20);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 
v.resize(5);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 1 1 1 1 
//指定⼤⼩⼩于当前的size时,再指定初始化内容时不会修改原始内容
v.resize(3, 3);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}//1 1 1return 0;}

3.reserve

reserve只负责开辟空间,如果确定知道需要⽤多少空间,reserve可以缓解vector增容的代价缺陷问题。 使⽤reserve()函数可以更改调⽤对象的capacity的⼤⼩,注意,如果指定⼤⼩⼩于当前的capacity时,则不会做任何 处理

int main(){vector<int> v(10, 1);cout << "原始⼤⼩:\n";cout << v.capacity() << endl;cout << v.size() << endl;cout << "扩容到20:\n";v.reserve(20);cout << v.capacity() << endl;cout << v.size() << endl;cout << "扩容到5:\n";v.reserve(5);cout << v.capacity() << endl;cout << v.size() << endl;return 0;}
输出结果:
原始⼤⼩:
1010
扩容到20:
2010
扩容到5:
2010

6.vector类中的数据遍历操作

void test2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);
//迭代器遍历
//指明迭代器类型
vector<int>::iterator it1 = v.begin();while (it1 != v.end()) {cout << *it1 <<" ";it1++;}cout << endl;//1 2 3 4//下标遍历
for (size_t i = 0; i < v.size(); i++) {cout << v[i] << " ";}cout << endl;//1 2 3 4//范围forfor(auto &e : v){cout << e <<" ";}cout << endl;//1 2 3 4}int main(){test2();}

6.2 operator 与at()函数

6.3 正向遍历begin()和end()迭代器——⾮const

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v(10, 1);//正向迭代器——⾮constvector<int>::iterator it = v.begin();while (it != v.end()){*it = 2;//可修改
cout << *it << " ";it++;}return 0;}
输出结果:
2 2 2 2 2 2 2 2 2 2

6.4逆向遍历rbegin()和rend()迭代器——⾮const

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//逆向迭代器——⾮constvector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){(*rit)++;//可修改
cout << *rit << " ";
rit++;}return 0;}
输出结果:
5 4 3 2

6.5 assign()函数

//使⽤⼀个对象的迭代器区间为调⽤对象分配内容
#include <iostream>#include <vector>using namespace std;int main(){//vector<int> v(5, 1);vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto num : v){cout << num << " ";}
cout << endl;vector<int> v1(10, 2);//v.assign(v1.begin(), v1.end());v.assign(v1.begin(), v1.end());for (auto num : v){cout << num << " ";}return 0;}
输出结果:
1 2 3 42 2 2 2 2 2 2 2 2 2//指定n个内容为调⽤对象分配
#include <iostream>#include <vector>using namespace std;int main(){//vector<int> v(5, 1);vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto num : v){cout << num << " ";}cout << endl;//vector<int> v1;//v1.push_back(5);//v1.push_back(6);//v1.push_back(7);//v1.push_back(8);//v.assign(v1.begin(), v1.end());v.assign(10, 5);for (auto num : v){cout << num << " ";}return 0;}
输出结果:
1 2 3 45 5 5 5 5 5 5 5 5 5

7.插入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函数的返回值来解决,我们会返回更新后的迭代器,这样就可以访问该位置了。

7.2push_back可以直接复用insert进行实现

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

7.3push_back与pop_back函数的测试

//在指定的的迭代器位置后插⼊内容val#include <iostream>#include <vector>using namespace std;
int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.insert(v.begin() + 3, 5);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}return 0;}
输出结果:
1 2 3 41 2 3 5 4

7.4在指定的迭代器位置后开始插⼊n个val

//在指定的迭代器位置后开始插⼊n个val#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.insert(v.begin() + 3, 5, 10);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}return 0;}
输出结果:
1 2 3 41 2 3 10 10 10 10 10 4

7.5在指定的迭代器位置后开始插⼊⼀个其他对象对应的迭代器区间中的内容

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<double> v1;v1.push_back(5.2);v1.push_back(6.3);v1.push_back(7.4);v1.push_back(8.5);//根据调⽤对象的类型决定强制转换的类型
v.insert(v.begin() + 3, v1.begin(), v1.end());//将double强制转换成int类型存⼊int类型的vector对象
for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v1.insert(v1.begin() + 3, v.begin(), v.end());//将int强制转换成double类型存⼊double类型的vector
对象
}for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}return 0;
输出结果:
1 2 3 41 2 3 5 6 7 8 45.2 6.3 7.4 1 2 3 5 6 7 8 4 8.5

8.删除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()之后迭代器失效问题

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

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

8.2 删除指定位置的⼀个数据

//删除指定位置的⼀个数据
#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 2 3 4vector<int>::iterator it = v.begin() + 1;v.erase(it);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 3 4//不可以再删除迭代器⼀开始指向的位置,存在迭代器失效问题
//v.erase(it);//如果还需要删除下标为1的位置需要再将迭代器更新
it = v.begin() + 1;v.erase(it);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";//1 4}return 0;}

8.3 删除迭代器区间中的内容

 //删除迭代器区间中的内容
#include <iostream>#include <vector>
using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 2 3 4v.erase(v.begin() + 2, v.end());for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 2return 0;}

9.swap函数

使⽤swap()函数可以交换调⽤对象和指定对象中的数据

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>    
v1(5, 1);cout << "交换前:\n";cout << "v的size:" << v.size() << endl;//4cout << "v的capacity:" << v.capacity() << endl;//4for (auto num : v){cout << num << " ";}cout << endl;//1 2 3 4cout << "v1的size:" << v1.size() << endl;//5cout << "v1的capacity:" << v1.capacity() << endl;//5
for (auto num : v1){cout << num << " ";}//1 1 1 1 1v.swap(v1);cout << "\n交换后:\n";cout << "v的size:" << v.size() << endl;//5cout << "v的capacity:" << v.capacity() << endl;for (auto num : v){cout << num << " ";}//11111cout << endl;cout << "v1的size:" << v1.size() << endl;//4cout << "v1的capacity:" << v1.capacity() << endl;//4for (auto num : v1){cout << num << " ";}//1234return 0;}

10.find函数

#include <iostream>#include <vector>#include <algorithm>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = find(v.begin(), v.end(), 3);
cout << *it << endl;//3return 0;}

11.某帅哥做的笔记——pdf

vector

相关文章:

【STL】 vector的底层实现

1.vector的模拟代码完整实现&#xff08;后面会拆分开一个一个细讲&#xff09; #pragma once #include<assert.h>// 抓重点namespace bit {/*template<class T>class vector{public:typedef T* iterator;private:T* _a;size_t _size;size_t _capacity;};*/templa…...

责任链模式:解耦职责,优化请求处理

在软件设计中&#xff0c;如何有效地处理复杂的请求是一个重要的课题。 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;提供了一种解耦请求发送者和接收者的方法&#xff0c;使得多个对象都有机会处理请求&#xff0c;从而达到灵活和可扩展的设计。 什么…...

【Scene Transformer】scene transformer论文阅读笔记

文章目录 序言(Abstract)(Introduction)(Related Work)(Methods)(Scene-centric Representation for Agents and Road Graphs)(Encoding Transformer)(Predicting Probabilities for Each Futures)(Joint and Marginal Loss Formulation) (Results)(Discussion)(Questions) sce…...

ESP32在ESP-IDF环境下禁用看门狗

最近使用了一款ESP32的开发板。但在调试时发现出现许多看门狗复位事件&#xff1a; E (8296) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: E (8296) task_wdt: - IDLE (CPU 0) E (8296) task_wdt: Tasks curre…...

基于 uniapp html5plus API,怎么把图片保存到相册

要将图片保存到相册中&#xff0c;可以使用HTML5 API中的plus.gallery.save方法。以下是一个示例代码&#xff0c;展示如何将图片保存到手机相册&#xff1a; // 图片的URL&#xff0c;可以是本地路径或网络路径 var imageUrl path/to/your/image.jpg;// 调用plus.gallery.sa…...

3.特征工程-特征抽取、特征预处理、特征降维

文章目录 环境配置&#xff08;必看&#xff09;头文件引用1.数据集: sklearn代码运行结果 2.字典特征抽取: DictVectorizer代码运行结果稀疏矩阵 3.文本特征抽取(英文文本): CountVectorizer()代码运行结果 4.中文文本分词(中文文本特征抽取使用)代码运行结果 5.中文文本特征抽…...

RISC-V (五)上下文切换和协作式多任务

任务&#xff08;task&#xff09; 所谓的任务就是寄存器的当前值。 -smp后面的数字指的是hart的个数&#xff0c;qemu模拟器最大可以有8个核&#xff0c;此文围绕一个核来讲。 QEMU qemu-system-riscv32 QFLAG -nographic -smp 1 -machine virt -bios none 协作式多任务 …...

Cornerstone加载本地Dicom文件第二弹 - Blob篇

&#x1f340; 引言 当我们刚接触Cornerstone或拿到一组Dicom文件时&#xff0c;如果没有ImageID和后台接口&#xff0c;可能只是想简单测试Cornerstone能否加载这些Dicom文件。在这种情况下&#xff0c;可以使用本地文件加载的方法。之前我们介绍了通过node启动服务器请求文件…...

C语言中整数类型及其类型转换

1.数据的存储和排列 是的&#xff0c;在C语言中&#xff0c;整数类型通常以补码&#xff08;twos complement&#xff09;形式存储在内存中。这是因为补码表示法在处理有符号整数的加减运算上更为简便和高效。 2.有符号数和无符号数之间的转换 在C语言中&#xff0c;有符号数和…...

powerjob连接postgresql数据库(支持docker部署)

1.先去pg建一个powerjob-product库 2.首先去拉最新的包&#xff0c;然后找到server模块&#xff0c;把mysql的配置文件信息替换成pg的 spring.datasource.hikari.auto-committrue spring.datasource.remote.hibernate.properties.hibernate.dialecttech.powerjob.server.pers…...

浅谈位运算及其应用(c++)

目录 一、位运算的基础&#xff08;一&#xff09;位与&#xff08;&&#xff09;&#xff08;二&#xff09;位或&#xff08;|&#xff09;&#xff08;三&#xff09;位异或&#xff08;^&#xff09;&#xff08;四&#xff09;位取反&#xff08;~&#xff09;&#x…...

Git版本管理中下列不适于Git的本地工作区域的是

Git版本管理中下列不适于Git的本地工作区域的是 A. 工作目录 B. 代码区 C. 暂存区 D. 资源库 选择B Git本地有四个工作区域&#xff1a; 工作目录&#xff08;Working Directory&#xff09;、 暂存区(Stage/Index)、 资源库(Repository或Git Directory)、 git仓库(Remote Di…...

webGL + WebGIS + 数据可视化

webGL&#xff1a; 解释&#xff1a;用于在浏览器中渲染 2D 和 3D 图形。它是基于 OpenGL ES 的&#xff0c;提供了直接操作 GPU 的能力。 库&#xff1a; Three.jsBabylon.jsPixiJSReglGlMatrixOsgjs WebGIS&#xff1a; 解释&#xff1a;用于在 Web 浏览器中处理和展示地…...

职场“老油条”的常规操作,会让你少走许多弯路,尤其这三点

有句话说得好&#xff1a;“在成长的路上&#xff0c;要么受教育&#xff0c;要么受教训。” 挨过打才知道疼&#xff0c;吃过亏才变聪明&#xff0c;从职场“老油条”身上能学到很多经验&#xff0c;不一定全对&#xff0c;但至少有可以借鉴的地方&#xff0c;至少能让你少走…...

Ceres Cuda加速

文章目录 一、简介二、准备工作三、实现代码四、实现效果参考资料一、简介 字Ceres2.2.1版本之后,作者针对于稠密矩阵的分解计算等操作进行了Cuda加速,因此这里就基于此项改动测试一下效果。 二、准备工作 1、首先是需要安装Cuda这个英伟达第三方库,https://developer.nvidi…...

微信小程序生成小程序转发链接,携带参数跳转到另外一个页面

🤵 作者:coderYYY 🧑 个人简介:前端程序媛,目前主攻web前端,后端辅助,其他技术知识也会偶尔分享🍀欢迎和我一起交流!🚀(评论和私信一般会回!!) 👉 个人专栏推荐:《前端项目教程以及代码》 ✨一、前言 需求:在页面A生成分享链接(携带参数),分享到微信…...

图解RocketMQ之消息如何存储

大家好&#xff0c;我是苍何。 人一辈子最值得炫耀的不应该是你的财富有多少&#xff08;虽然这话说得有点违心&#xff0c;呵呵&#xff09;&#xff0c;而是你的学习能力。技术更新迭代的速度非常快&#xff0c;那作为程序员&#xff0c;我们就应该拥有一颗拥抱变化的心&…...

2024年中国信创产业发展白皮书精简版

获取方式&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEHMfcCfJm4A40vzrewoCw?pwda5u1 提取码&#xff1a;a5u1 得益于中国数字经济的迅猛发展&#xff0c;2023年中国信创产业规模达20961.9亿元&#xff0c;2027年有望达到37011.3亿元&#xff0c;中国信创市场…...

Redis2-Redis常见命令

目录 Redis数据结构介绍 Redis通用命令 KEYS DEL EXISTS EXPIRE String类型 Key的层级格式 Hash类型 List类型 Set类型 SortedSet类型 Redis数据结构介绍 Redis是一个key-value的数据库&#xff0c;key一般是String数据库&#xff0c;value的类型多种多样 可以通过…...

一天攻克一个知识点 —— 设计模式之动态代理

一、设计模式之代理设计 代理设计是在Java开发中使用较多的一种设计模式&#xff0c;所谓的代理设计模式就是指一个代理主体操作真实主体&#xff0c;真实主体操作具体业务&#xff0c;代理主体负责给具体业务添砖加瓦。 就好比在生活中你有一套房子想要出租(你真实主体)&…...

数据采集与预处理【大数据导论】

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 数据采集与预处理前 必看 【大数据导论】—大数据序…...

白骑士的PyCharm教学进阶篇 2.2 高级调试技术

系列目录 上一篇&#xff1a;白骑士的PyCharm教学进阶篇 2.1 高效编码技巧 在Python开发中&#xff0c;调试是一个非常重要的环节。PyCharm作为一款功能强大的IDE&#xff0c;不仅提供了基本的调试功能&#xff0c;还包含了许多高级调试工具与技巧。本篇将详细介绍这些高级调试…...

[网鼎杯]2018Unfinish

使用ctf在线靶场https://adworld.xctf.org.cn/home/index。 进入靶场&#xff0c;发现是一个登录页面。 使用awvs进行扫描&#xff0c;发现存在login.php和register.php&#xff0c;并且register.php存在sql注入漏洞。 访问一下register.php试试&#xff0c;发现是一个注册页面…...

Java算法-力扣leetcode-383. 赎金信

383. 赎金信 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1a…...

使用idea对spring全家桶的各种项目进行创建

目录 1. 简介2. spring2.1 简介2.2 创建 3. springmvc3.1 介绍3.2 创建 4. springboot4.1 简介4.2 创建&#xff08;仅仅就其中一种&#xff09; 5. 其他&#xff1a;maven6. 参考链接 1. 简介 因为总是分不清spring全家桶&#xff0c;所以就在这里进行一个总结。 2. spring …...

FAT32、NTFS、FAT的区别

FAT&#xff08;File Allocation Table&#xff09; 特点 簇大小限制&#xff1a;FAT文件系统的簇大小是固定的&#xff0c;这限制了单个文件的大小和文件系统的效率。 存储效率&#xff1a;由于簇大小的限制&#xff0c;FAT文件系统在存储小文件时可能会浪费空间。 文件系统结…...

捉虫笔记(二)之 杀软请你自重点

捉虫笔记&#xff08;二&#xff09;之 杀软请你自重点 前一篇文章介绍了如何配置符号&#xff0c;这一篇文章我们来个实战。 1 现象 在我们的程序中利用robocopy进行文件的复制。但是QA反馈&#xff0c;只要进行了备份操作&#xff0c;整个进程就会卡住。但是奇怪的是只有他…...

python学习之路 - python的函数

目录 一、python函数1、函数介绍2、函数的定义3、函数的参数4、函数的返回值5、函数说明文档6、函数的嵌套调用7、变量的作用域8、综合案例9、函数与方法的区别 二、python函数进阶1、函数多返回值2、函数多种传参方式a、位置参数b、关键字参数c、缺省参数d、不定长参数 3、匿名…...

使用SpringBoot+Vue3开发项目(2)---- 设计文章分类的相关接口及页面

目录 一.所用技术栈&#xff1a; 二.后端开发&#xff1a; 1.文章分类列表渲染&#xff1a; 2.新增文章分类&#xff1a; 3.编辑文章分类&#xff1a; 4.删除文章分类 &#xff1a; 5.完整三层架构后端代码&#xff1a; &#xff08;1&#xff09;Controller层&#xff1a…...

Layui---toolbar与 tool的区别

table.on(toolbar): table.on(toolbar)&#xff1a; 这个事件监听器是用来处理表格工具栏的事件。工具栏通常位于表格的上方&#xff0c;可以包含添加、删除、导出等按钮。当用户与这些工具栏中的按钮交互时&#xff0c;比如点击一个按钮来添加新行或者进行搜索操作&#xff0c…...