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

【C++】vector的底层封装和实现

目录

  • 目录
    • 前言
    • 基本框架
    • 迭代器
    • 容量
      • 第一个测试,野指针异常
      • 第二轮测试,浅拷贝的问题
    • 元素访问
    • 修改操作
      • push_back
      • insert
        • 迭代器失效问题
      • erase
    • 默认成员函数
      • 构造函数
        • 双重构造引发调用歧义
      • 拷贝构造
      • 赋值重载
      • 析构函数
    • 源码
    • end

目录

前言

废话不多说,我们直接来模拟实现vector的底层实现,有了上篇文章string的底层封装和模拟实现,相信大家已经对stl的容器的底层有了一定的了解

基本框架

namespace bit {template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;// 主要接口函数private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}
  • 这里我们的三个成员变量参考源码中的实现方式,用指针来模拟实现。
  • 并且采用缺省参数的形式将它们都初始化为nullptr,这样当我们后面在写 构造函数和析构函数 的时候就不需要再去做初始化了

迭代器

  • 这里就很简单的返回我们指向开头的指针和指向最后一个元素的指针就行了
iterator begin()
{return _start;
}iterator end()
{return _finish;
}const_iterator begin()  const
{return _start;
}const_iterator end()	const
{return _finish;
}

容量

  • 如何获取元素个数和内存容量,在C语言中我们讲过指针减去指针就是他们之间的元素个数,如此即可
size_t size()
{return _finish - _start;
}size_t capacity()
{return _end_of_storage - _start;
}
  • 这里我们来重点说一下这个reserve扩容函数,他牵扯到一个很大的问题。

在这里插入图片描述

  • 我们这里再写一个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++;
}

第一个测试,野指针异常

  • 测试代码
bit::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);

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

  • 可以看到,程序崩溃了,那是什么原因了,不妨调试看一下
    在这里插入图片描述
  • 插入的时候对空指针解引用,我们再一步步看看_finish指针为啥是空指针
_finish = _start + size();
  • 这个时候就知道了,我们扩容的时候_start已经更新到tmp新空间的位置,但是更新_finish的时候,size()函数的结构是这样的
    在这里插入图片描述
  • 但是现在我们的_start已经是更新到tmp新空间的位置上去了,这时候_finish是旧空间,两个指针不是同一块空间相减就是一个随机值
    在这里插入图片描述
  • 那么又如何来解决这个问题呢?
  • 根据上面的描述,我们发现其实就是因为更新_finish我们调用了size函数造成的问题,那么这个时候我们其实就是想要知道元素个数,但是必须要在_start更新之前,所以我们就在_start更新之前获取元素个数即可
if (n > capacity())
{// 先保存一下原先的size()size_t sz = size();T* tmp = new T[n];		// 开一块新空间if (_start){memcpy(tmp, _start, sizeof(T) * size());delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;
}

第二轮测试,浅拷贝的问题

  • 下面是我们要进行第二轮测试的代码,内部类型使用的是 string类
void test_vector2()
{bit::vector<string> v;v.push_back("11111");v.push_back("22222");v.push_back("33333");v.push_back("44444");for (auto e : v){cout << e << " ";}cout << endl;
}
  • 运行起来看并没有什么问题
    在这里插入图片描述
  • 但是呢当我再去push_back(“55555”)的时候程序却出现了问题,这个时候发生了扩容

在这里插入图片描述

  • 就是对于自定义类型,虽然我们的确是tmp独立开了一块新空间,但是memcpy函数就是把指针_str的值拷贝过来,导致原来的_str和tmp的_str指向同一块空间。就会发生两个指针指向同一块空间。
  • 那么在执行下面这句代码的时候,先会去把this指针的_str指向的那块空间析构掉,这个时候因为他们指向的是同一块空间,改变_str也同时更改了tmp中的_str
delete[] _start;

在这里插入图片描述

  • 那么知道了是什么问题,我们又该如何解决这个问题呢?
  • 我们知道导致这个原因的就是因为memcpy是浅拷贝,那么我们实现一个深拷贝就行了

这里我们就直接执行下面的代码:

for (size_t i = 0; i < OldSize; i++)
{tmp[i] = _start[i];
}
  • 这里的逻辑就是把_start的每个值赋值给tmp用来更新新的_start,这个时候就要重载一下赋值重载完成深拷贝,这会在后面介绍,请往下看。

接下来再看一下resize这个函数的实现

void resize(size_t n, const T& val = T())
{if (n <= size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;_finish++;} }
}
  • 如果重置的长度小于原来的长度,那么直接把_finish更新到_start + n的位置,就是n个长度就行
  • 如果大于原来的长度,直接扩容到n个,如果扩容到n个后_finish还是小于n个的时候,再把_finish更新到n个。

元素访问

  • 对于元素访问的话我们最常用的就是下标 + []的形式,这里给出两种,一个是const版本和非const版本
T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}T& operator[](size_t pos)	const
{assert(pos < size());return _start[pos];
}

修改操作

push_back

void push_back(const T& x)
{if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;++_finish;
}
  • 这一块的逻辑非常简单,当最后一个元素的指针和容量的指针位置相同的时候,就需要扩容,否则直接插入,更新_finish指针就行了

insert

void insert(iterator pos, const T& x)
{assert(pos >= _start && pos <= _finish);// 1.首先考虑扩容逻辑if (_finish == _end_of_storage){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}// 2.挪动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;
}
  • 这一块同理,插入数据先考虑是否需要扩容
  • 然后把pos位置后面的数据往后面挪,知道pos位置插入x即可。
迭代器失效问题

1.这里指定位置插入函数,如果空间不管扩容的时候就出现了迭代器失效的问题
2.如果不更新pos的位置,那我们还在释放的旧空间里面插入,就会发生访问野指针!

在这里插入图片描述

  • 那么如何去解决这个问题呢?

首先我们要明确导致这个问题发生的就是pos没有正确的更新,pos需要更新到新空间和原空间的相应位置,那么我们就算出旧空间中pos的相对位置,在新空间开辟后,把pos更新到新空间的相对位置就行了

  • 但是呢就上面这样还不够,我们只解决了内部迭代器失效的问题,而外部迭代器失效的问题并没有很好地解决。
  • 外部迭代器又是个什么东西,接下来看看这段代码
bit::vector<int>::iterator it = v.begin();
v.insert(it, 33);
bit::print(v);cout << *it << endl;bit::print(v);
  • 可以看到,在使用完这个这个迭代器之后再去访问就出现了问题
    在这里插入图片描述
  • 这是因为,形参迭代器的传值并不能改变外面的实参迭代器。
  • 有的同学就会说,那简单,传个引用就行了,但是你再来看看这个情况
v.insert(v.begin() + 3, 6);

在这里插入图片描述

在这里插入图片描述

erase

  • 对于【erase】来说,我们也是需要先去挪动数据的,但是在这里呢我们需要从前往后挪,也是防止造成覆盖的情况
void erase(iterator pos)
{assert(pos >= _start && pos < _finish);iterator end = pos + 1;// 移动覆盖while (end != _finish){*(end - 1) = *end;++end;}--_finish;
}
  • 立马来测试一下

在这里插入图片描述

  • 看起来并没啥问题,那接下来看看下面的2个场景
  • 场景1:我们在中间插入两个偶数,现在我们要对容器中的偶数进行删除,可以看看下方结果
    在这里插入图片描述
    在这里插入图片描述
  • 可以看到发生了逻辑错误,我们的目的是把所有的偶数都删除了,可是现在容器中还有偶数!
    Why?
    如下图,我们删除一个数后,会把他前面的一个数挪到被删除数字的位置,那么这个时候it++,如果被挪到到删除位置的数是一个偶数就会漏掉这个数的判断。
    在这里插入图片描述
  • 场景2:如果最后一个元素是偶数,那么删除会咋样呢?如图看看我们的代码,那这样把最后一个元素删除后,不就越界访问了吗,it 会永远不等于 _finish
    在这里插入图片描述
  • 这个时候有人说,我们就要修改一下,当删除偶数的时候,不要让it++,这是对的,但还缺点东西
    在这里插入图片描述
  • 可是,万一别人底层实现erase很多次,容器的数据变少了,别人要缩容呢? 缩容是异地缩容,就是重新开一段比之前小的空间,把原来的空间数据拷贝过去,最后释放原来的空间,异地缩容是因为C++开辟内存只能是连续的内存,所以释放的时候不能只释放一部分。这时候it不就又变成,inset中的那样野指针的问题导致迭代器失效了吗?
    在这里插入图片描述
  • 这个时候,就返回被删除元素的下一个元素的位置值,这里返回pos,是因为我们的算法是被删除元素的下一个位置元素移到这个被删除元素的位置,所以被删除元素的下一个元素的位置就是pos本身.当然这里我们没有实现缩容,但是如果这里缩容,就会更新pos的位置,把新pos返回的
    在这里插入图片描述

默认成员函数

构造函数

  • 首先的话一定是构造函数,有参构造是一定要实现的,因为这里的逻辑和resize()是类似的,因此我们直接去做一个复用即可
// 有参构造
vector(size_t n, const T& val = T())
{resize(n, val);
}
  • 那有同学可能会问,三个私有成员变量不需要去做初始化吗?
  • 这个时候我们的缺省值就发挥作用了,很好的避免了忘记初始化三个成员变量的问题
private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;
  • 除了上面这种初始化,我再介绍一种方法:那就是使用 迭代器区间
// [first, last)
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);++first;}
}
  • 复用push_back接口就行了
  • 我们再补充一个构造
		vector(initializer_list<T> lt):_start(nullptr),_finish(nullptr),_endofstorage(nullptr){//initializer_list底层就是自己开了一块空间,类似数组这种,那么他就支持迭代器for (auto e : lt){push_back(e);}}
  • 这个考前使用迭代器就行,他底层是类似数组
双重构造引发调用歧义

在这里插入图片描述

  • 那么如何解决呢?我们模板匹配还有个原则就是有现成吃现成的,如果有int类型的构造,模板就不用去实例化,所以重载一个int类型的,让他匹配

在这里插入图片描述

拷贝构造

vector(const vector<T>& v)
{reserve(v.capacity()); //和被拷贝的对象开一样大的空间,防止一直扩容,提高效率for (auto& e : v){push_back(e);}
}
  • push_back扩容的时候完成深拷贝

赋值重载

vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}
  • 这里的逻辑类似string里面的,this想要得到v的资源并且把原来的资源抛弃,得到v的资源直接交换他们指向的指针就行了。由于v是局部变量,调用完会析构,就把this的资源析构了。

在这里插入图片描述

析构函数

~vector()
{if (_start){delete[] _start;	//同一块空间_start = _finish = _endofstorage = nullptr;}
}

源码

#pragma once
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
namespace bit
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector():_start(nullptr),_finish(nullptr),_endofstorage(nullptr){}vector(initializer_list<T> lt):_start(nullptr),_finish(nullptr),_endofstorage(nullptr){//initializer_list底层就是自己开了一块空间,类似数组这种,那么他就支持迭代器for (auto e : lt){push_back(e);}}vector(const vector<T>& v){reserve(v.capacity()); //和被拷贝的对象开一样大的空间,防止一直扩容,提高效率for (auto& e : v){push_back(e);}}template <class InputIterator>	//类模板的成员函数也可以是一个函数模板, 这里的迭代器可以是任何类型如:string, list的迭代器构造vector(InputIterator first, InputIterator last)		  {while (first != last){push_back(*first);first++;}}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}void swap(vector<T>& tmp){std::swap(_start, tmp._start);std::swap(_finish, tmp._finish);std::swap(_endofstorage, tmp._endofstorage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;	//同一块空间_start = _finish = _endofstorage = nullptr;}}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}T& operator[](size_t i){assert(i < size());return _start[i];}const T& operator[](size_t i) const{assert(i < size());return _start[i];}size_t size() const{return _finish - _start;}size_t capacity() const{return _endofstorage - _start;}void reserve(size_t n){size_t	OldSize = size();if (n > capacity()){T* tmp = new T[n];for (size_t i = 0; i < OldSize; i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = _start + OldSize;_endofstorage = _start + n;}}void push_back(const T& x){if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;++_finish;}bool empty() const{return size() == 0;}void pop_back(){assert(!empty()); --_finish;}void resize(size_t n, const T& val = T()){if (n <= size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;_finish++;} }}iterator insert(iterator pos, const T& x)	//这里改成引用我希望形参可以改变实参{assert(pos >= _start && pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}iterator end = _finish;while (end != pos){*end = *(end - 1);end--;}*pos = x;_finish++;return pos;}iterator erase(iterator pos){assert(pos >= _start && pos < _finish);iterator i = pos + 1;while (i < _finish){*(i - 1) = *i;i++;}_finish--;return pos;}private:iterator _start = nullptr;	//写一个类一定要把缺省参数写上,防止初始化列表没初始化导致的一系列越权访问问题iterator _finish = nullptr;iterator _endofstorage = nullptr;};
}

end

感谢阅读,希望对大家有所帮助。快去实现一下吧

相关文章:

【C++】vector的底层封装和实现

目录 目录前言基本框架迭代器容量第一个测试&#xff0c;野指针异常第二轮测试&#xff0c;浅拷贝的问题 元素访问修改操作push_backinsert迭代器失效问题 erase 默认成员函数构造函数双重构造引发调用歧义 拷贝构造赋值重载析构函数 源码end 目录 前言 废话不多说&#xff0…...

AI前端组件库Ant DesIgn X

Ant Design X AI&#xff1a;体验新秩序 Ant Design 团队精心打造 RICH 设计范式&#xff0c;为 AI 界面提供卓越解决方案&#xff0c;引领智能交互新体验。 设计语言与理论 官网&#xff1a; Ant Design X - 轻松打造 AI 驱动的界面。 AI 设计范式 —— RICH 是我们在蚂蚁…...

BGP路由协议之解决 IBGP 水平分割带来的问题

主要有以下 3 种方案&#xff1a; 全互联 &#xff1a;配置量大、耗费资源联邦&#xff1a; 配置量大、邻居会重建、中断时间较长RR 路由反射器&#xff1a;目前主流使用、简单、好用 联邦 IBGP 水平分割问题用与防止 AS 内部产生环路&#xff0c;在很大程度上杜绝了 IBGP 路…...

基于Java的人脸识别在线考试系统(jsp+springboot+mysql8.x)

基于Java的人脸识别在线考试系统(jspspringbootmysql8.x) 在线考试系统提供全面的考试管理和用户管理功能。登录界面支持管理员、教师和学生三种身份验证&#xff0c;确保不同用户访问相应的功能模块。系统自动组卷功能允许管理员根据不同科目和题型&#xff0c;如单选题、多选…...

如何对LLM大型语言模型进行评估与基准测试

基础概念 这几年&#xff0c;随着生成式 AI 和大型语言模型&#xff08;LLMs&#xff09;的兴起&#xff0c;AI 领域整体迎来了一波大爆发。 随着各种基于 LLM 的应用程序在企业里落地&#xff0c;人们开始需要评估不同推理部署方案的性价比。 LLM 应用的部署成本&#xff0c;…...

C语言内存函数和数据在内存的存储

一、内存操作函数深度解析 函数名原型核心特性典型应用场景注意事项memcpyvoid* memcpy(void* dest, const void* src, size_t num)内存块无重叠复制&#xff0c;性能高数组拷贝、结构体复制1. 必须确保目标空间足够 2. 不支持重叠内存&#xff08;用memmove替代&#xff09; …...

ChatGPT之智能驾驶问题讨论

ChatGPT之智能驾驶问题讨论 1. 源由2. 问题&#xff1a;2.1 智能驾驶级别定义&#x1f697; L2&#xff08;部分自动化&#xff0c;Partial Automation&#xff09;&#x1f916; L3&#xff08;有条件自动化&#xff0c;Conditional Automation&#xff09;&#x1f6f8; L4&a…...

【PalladiumZ2 使用专栏 1 -- 波形 trigger 抓取详细介绍】

文章目录 Palladium Z2 OverviewPalladium 波形抓取Palladium 波形存放文件创建Palladium Trigger 断点设置Palladium 加探针并 dumpPalladium 波形查看 Palladium Z2 Overview Cadence Palladium Z2 是 Cadence 推出的企业级硬件仿真加速平台&#xff0c;旨在应对复杂 SoC 设…...

elasticsearch 8设置验证登录查询

最近总是困扰于9200网络勒索,老是在捣乱,动不动给我清理了index,实在是费劲,今天研究了下config配置,设置ca验证。 以下是完整的步骤和配置,确保生成的证书文件与elasticsearch.yml的配置一致: 1. 生成CA证书 运行以下命令生成CA证书:让输入账号或密码请直接回车。 …...

为什么使用了CDN源服务器需要关闭防火墙?

在网站运营过程中&#xff0c;不少站长会遇到这样的困惑&#xff1a;当使用 CDN 源服务器时&#xff0c;好像就得关闭源服务器的防火墙&#xff0c;不然就状况百出。这背后究竟是什么原因呢&#xff1f; 当你在浏览网页时&#xff0c;要是看到 “502 - 服务暂时不可用” 的提…...

Android 学习之 Navigation导航

1. Navigation 介绍 Navigation 组件 是 Android Jetpack 的一部分&#xff0c;用于简化应用内导航逻辑&#xff0c;支持 Fragment、Activity 和 Compose 之间的跳转。核心优势&#xff1a; 单 Activity 架构&#xff1a;减少 Activity 冗余&#xff0c;通过 Fragment 或 Com…...

初识 Three.js:开启你的 Web 3D 世界 ✨

3D 技术已经不再是游戏引擎的专属&#xff0c;随着浏览器技术的发展&#xff0c;我们完全可以在网页上实现令人惊艳的 3D 效果。而 Three.js&#xff0c;作为 WebGL 的封装库&#xff0c;让 Web 3D 的大门向更多开发者敞开了。 这是我开启这个 Three.js 专栏的第一篇文章&…...

PyTorch 笔记

简介与安装 PyTorch 是一个开源的 Python 机器学习库&#xff0c;基于 Torch 库&#xff0c;底层由C实现&#xff0c;应用于人工智能领域&#xff0c;如计算机视觉和自然语言处理。 PyTorch 最初由 Meta Platforms 的人工智能研究团队开发&#xff0c;现在属 于Linux 基金会的…...

day24学习Pandas库

文章目录 三、Pandas库4.函数计算3遍历3.1.遍历Series对象3.2.遍历DataFrame对象 4排序4.1 sort_index4.2 sort_values 5.去重drop_duplicates6.先分组在计算6.1 groupby6.2 filter过滤 7.合并未完待续.. 三、Pandas库 4.函数计算 3遍历 3.1.遍历Series对象 在讲解Series部…...

AI日报 - 2025年4月8日

AI日报 - 2025年4月8日 &#x1f31f; 今日概览&#xff08;60秒速览&#xff09; ▎&#x1f916; 模型进展 | Llama 4发布引爆讨论 (性能、应用、部署、训练争议)&#xff0c;OpenAI保持高速迭代&#xff0c;香港大学推Dream 7B扩散模型。 Meta Llama 4 Scout & Maveric…...

Linux学习笔记(2) 命令基础:从概念到实践(期末,期中复习笔记全)

前言 一、认识命令行与命令 二、Linux 命令的基础格式 三、命令示例解析 &#xff08;1&#xff09;ls -l /home/itheima &#xff08;2&#xff09;cp -r test1 test2 四结语 前言 在 Linux 系统的世界里&#xff0c;命令行是与系统交互的重要方式。熟练掌握 Linux 命令…...

langgraph简单Demo4(checkpoint检查点)

在 langgraph 里&#xff0c;检查点&#xff08;checkpoint&#xff09;是一项重要的功能&#xff0c;它能够记录工作流在执行过程中的中间状态。当工作流因某些原因中断时&#xff0c;可以从检查点恢复继续执行&#xff0c;避免从头开始&#xff0c;提升效率。 示例&#xff…...

【题解】AtCoder AT_abc400_c 2^a b^2

题目大意 我们定义满足下面条件的整数 X X X 为“好整数”&#xff1a; 存在一个 正整数 对 ( a , b ) (a,b) (a,b) 使得 X 2 a ⋅ b 2 X2^a\cdot b^2 X2a⋅b2。 给定一个正整数 N N N&#xff08; 1 ≤ N ≤ 1 0 18 1\le N\le 10^{18} 1≤N≤1018&#xff09;&#xff…...

七种驱动器综合对比——《器件手册--驱动器》

目录 九、驱动器 概述 定义 功能 分类 1. 按负载类型分类 2. 按功能特性分类 工作原理 优势 应用领域 详尽阐述 1 隔离式栅极驱动器 定义 工作原理 应用场景 优势 2 变压器驱动器 定义 工作原理 应用场景 优势 设计注意事项 3 LED驱动 定义 功能与作用 应用场景 设计…...

GStreamer开发笔记(一):GStreamer介绍,在windows平台部署安装,打开usb摄像头对比测试

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/147049923 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、O…...

西湖大学团队开源SaProt等多款蛋白质语言模型,覆盖结构功能预测/跨模态信息搜索/氨基酸序列设计等

2025 年 3 月 22—23 日&#xff0c;上海交通大学「AI 蛋白质设计峰会」正式举行。 本次峰会汇聚了来自清华大学、北京大学、复旦大学、浙江大学、厦门大学等知名高校的 300 多位专家学者&#xff0c;以及 200 余位行业领军企业代表和技术研发人员&#xff0c;深入探讨了 AI 在…...

ansible+docker+docker-compose快速部署4节点高可用minio集群

目录 github项目地址 示例服务器列表 安装前 修改变量文件group_vars/all.yml 修改ansible主机清单 修改setup.sh安装脚本 用法演示 安装后验证 github项目地址 https://github.com/sulibao/ansible_minio_cluster.git 示例服务器列表 安装前 修改变量文件group_var…...

说话人分离中的聚类方法:深入解析Agglomerative聚类、KMeans聚类和Oracle聚类

说话人分离&#xff08;Speaker Diarization&#xff09;是将音频流根据说话人身份划分为同质片段的过程。这一过程中的关键步骤是聚类&#xff0c;即将说话人嵌入&#xff08;embeddings&#xff09;分组为不同的簇&#xff0c;每个簇代表一个独特的说话人。在pyannote.audio管…...

蓝桥杯真题——前缀总分、遗迹

蓝桥杯2024年第十五届省赛真题-前缀总分 题目描述 给定 n 个由小写英文字母组成的字符串 s1, s2, , sn &#xff0c;定义前缀总分为V ∑i<j P(si, sj) &#xff0c;其中 P(si, sj) 表示 si, sj 的最长公共前缀的长度。 小蓝可以选择其中一个字符串&#xff0c;并修改其…...

性能比拼: MySQL vs PostgreSQL

本内容是对知名性能评测博主 Anton Putra MySQL vs PostgreSQL Performance Benchmark (Latency - Throughput - Saturation) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 MySQL vs PostgreSQL 数据库性能对比** 在本内容中&#xff0c;我们将对比 MySQL 和 Pos…...

TypeScript 中的 infer 关键字用途

infer 是 TypeScript 中的高级类型关键字&#xff0c;主要用于条件类型中推断类型。它允许我们在条件类型的 extends 子句中声明一个类型变量&#xff0c;然后在该条件类型的 true 分支中使用这个推断出的类型。 1. 基本语法 type SomeType<T> T extends infer U ? U…...

关于Spring MVC中@RequestParam注解的详细说明,用于在前后端参数名称不一致时实现参数映射。包含代码示例和总结表格

以下是关于Spring MVC中RequestParam注解的详细说明&#xff0c;用于在前后端参数名称不一致时实现参数映射。包含代码示例和总结表格&#xff1a; 1. 核心作用 RequestParam用于显式绑定HTTP请求参数到方法参数&#xff0c;支持以下场景&#xff1a; 参数名不一致&#xff1…...

Spring Boot中Spring MVC相关配置的详细描述及表格总结

以下是Spring Boot中Spring MVC相关配置的详细描述及表格总结&#xff1a; Spring MVC 配置项详解 1. 异步请求配置 spring.mvc.async.request-timeout 描述&#xff1a;设置异步请求的超时时间&#xff08;单位&#xff1a;毫秒&#xff09;。默认值&#xff1a;未设置&…...

Shell脚本编程之正则表达式

一、概念 在 Shell 脚本中&#xff0c;正则表达式是一种强大且常用的文本处理工具&#xff0c;它可以用来匹配、搜索、替换和截取字符串。 正则表达式是由一些字符去描述规则&#xff0c;在正则表达式中有两类字符 (1)元字符(Meta Character)&#xff1a;Shell 环境中具有特殊含…...

spring-ai-openai调用Xinference1.4.1报错

1、Xinference 报错logs 此处是调用 /v1/chat/completions 接口 2025-04-06 15:48:51 xinference | return await dependant.call(**values) 2025-04-06 15:48:51 xinference | File "/usr/local/lib/python3.10/dist-packages/xinference/api/restful_api.py", …...

XC7K160T-2FFG676I Kintex‑7系列 Xilinx 赛灵思 FPGA 详细技术规格

XC7K160T-1FFG676I XC7K160T-1FFG676C XC7K160T-2FFG676C 1. 基本概述 XC7K160T-2FFG676I 属于 Xilinx Kintex‑7 系列 FPGA&#xff0c;该系列芯片采用 28nm &#xff08;HKMG&#xff09;工艺制造&#xff0c;旨在提供高性能与低功耗的平衡。该芯片主要面向对高速数据处理、…...

C++学习之udp通信

1.UDP特点 c /* udp 传输层协议, 和tcp是一样的 特点: 面向无连接的, 不安全的, 报式传输协议 1. 无连接: udp通信的时候不需要connect 1). 通信不需要建立连接 2). 如果想给对方发送数据, 只需要指定对方的IP和端口 2. udp会丢包 1). 数…...

2020年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析

2020年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛(China Undergraduate Mathematical Contest in Modeling)是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动,目的在于激励学生学习数学的积极性,提高学…...

【数据标准】数据标准化实施流程与方法-保障机制篇

导读&#xff1a;1、数据标准化保障机制&#xff08;组织架构、协作流程&#xff09;是​​战略落地的基石​​&#xff0c;确保责权分明与资源协同&#xff1b;2、数据标准化制度建设&#xff08;政策、标准、工具&#xff09;构建了​​统一治理框架​​&#xff0c;规范数据…...

ZLMediaKit部署与配置

ZLMediaKit编译 # 安装编译器 sudo apt install build-essential cmake# 其它依赖库 sudo apt-get install libssl-dev libsdl-dev libavcodec-dev libavutil-dev ffmpeg git cd /usr/local/srcgit clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit.git cd ZLMediaKit# …...

38、web前端开发之Vue3保姆教程(二)

三、Vue3语法详解 1、组件 1 什么是组件? 组件是 Vue.js 中最重要的概念之一。它是一种可复用的 Vue 实例,允许我们将 UI 拆分为独立的、可复用的部分。组件可以提高代码的组织性和可维护性。 2 创建组件 在 Vue 3 中,组件通常使用单文件组件(SFC)编写,其包含三个主…...

知识中台如何重构企业信息生态?关键要素解析

在信息化快速发展的时代&#xff0c;企业面临着如何高效整合和管理知识资源的挑战。知识中台作为企业信息管理的核心工具&#xff0c;正在帮助企业提升运营效率和创新力。本文将探讨知识中台如何重构企业信息生态&#xff0c;并解析其关键要素。 一、什么是知识中台&#xff1f…...

蓝桥杯python组备赛(记录个人模板)

文章目录 栈队列堆递归装饰器并查集树状数组线段树最近公共祖先LCAST表字典树KMPmanacher跳表(代替C STL的set)dijkstra总结 栈 用list代替 队列 用deque双端队列替代 堆 用heapq 递归装饰器 众所周知&#xff0c;python的递归深度只有1000&#xff0c;根本满足不了大部…...

C++的多态 - 下

目录 多态的原理 虚函数表 1.计算包含虚函数类的大小 2.虚函数表介绍 多态底层原理 1.父类引用调用 2.父类指针调用 3.动态绑定与静态绑定 单继承和多继承关系的虚函数表 函数指针 1.函数指针变量 (1)函数指针变量创建 (2)函数指针变量的使用 (3)两段有趣的代码 …...

XSS(跨站脚本攻击)

什么是 XSS 攻击&#xff1f; XSS 攻击&#xff08;Cross-Site Scripting&#xff09;是一种常见的网络攻击手段&#xff0c;攻击者通过在网站上注入恶意的 JavaScript 代码&#xff0c;让网站在用户的浏览器中执行这些恶意代码&#xff0c;进而达到 窃取信息、篡改网页内容 或…...

LLM Agents的历史、现状与未来趋势

引言 大型语言模型&#xff08;Large Language Model, LLM&#xff09;近年在人工智能领域掀起革命&#xff0c;它们具备了出色的语言理解与生成能力。然而&#xff0c;单纯的LLM更像是被动的“回答者”&#xff0c;只能根据输入给出回复。为了让LLM真正“行动”起来&#xff…...

最简rnn_lstm模型python源码

1.源码 GitCode - 全球开发者的开源社区,开源代码托管平台 不到120行代码&#xff0c;参考了《深度学习与交通大数据实战》3.2节。注意这本书只能在京东等在线商城网购&#xff0c;才能拿到相应的数据集和源码。我的是在当地新华书店买的——买清华出版社&#xff0c;记得这个…...

基于Android的图书借阅和占座系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 基于Android的图书借阅和占座系统设计的目的是为用户提供图书信息、图书馆、图书资讯等内容&#xff0c;用户可以进行图书借阅、预约选座等操作。 与PC端应用程序相比&#xff0c;图书借阅和占座系统的设计主要面向于广大用户&#xff0c;旨在为用户提供一个图书借阅及占…...

vue3+element-plus动态与静态表格数据渲染

一、表格组件&#xff1a; <template> <el-table ref"myTable" :data"tableData" :header-cell-style"headerCellStyle" header-row-class-name"my-table-header" cell-class-name"my-td-cell" :row-style"r…...

数据库50个练习

数据表介绍 --1.学生表 Student(SId,Sname,Sage,Ssex) --SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 --2.课程表 Course(CId,Cname,TId) --CId 课程编号,Cname 课程名称,TId 教师编号 --3.教师表 Teacher(TId,Tname) --TId 教师编号,Tname 教师姓名 --4.成绩…...

Open CASCADE学习|读取点集拟合样条曲线(续)

问题 上一篇文章已经实现了样条曲线拟合&#xff0c;但是仍存在问题&#xff0c;Tolerance过大拟合成直线了&#xff0c;Tolerance过大头尾波浪形。 正确改进方案 1️⃣ 核心参数优化 通过调整以下参数控制曲线平滑度&#xff1a; Standard_Integer DegMin 3; // 最低阶…...

HTML基础教程:创建双十一购物狂欢节网页

页面概况&#xff1a; 在这篇技术博客中&#xff0c;我将详细讲解如何使用HTML基础标签创建一个简单而美观的双十一购物狂欢节主题网页。我们将逐步分析代码结构&#xff0c;了解每个HTML元素的作用&#xff0c;以及如何通过HTML属性控制页面布局和样式。 页面整体结构 首先&…...

ES6 新增特性 箭头函数

简述&#xff1a; ECMAScript 6&#xff08;简称ES6&#xff09;是于2015年6月正式发布的JavaScript语言的标准&#xff0c;正式名为ECMAScript 2015&#xff08;ES2015&#xff09;。它的目标是使得JavaScript语言可以用来编写复杂的大型应用程序&#xff0c;成为企业级开发语…...

【C++算法】49.分治_归并_计算右侧小于当前元素的个数

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 315. 计算右侧小于当前元素的个数 题目描述&#xff1a; 解法 归并排序&#xff08;分治&#xff09; 当前元素的后面&#xff0c;有多少个比我小。&#xff08;降序&…...

Multi-class N-pair Loss论文理解

一、N-pair loss 对比 Triplet loss 对于N-pair loss来说&#xff0c;当N2时&#xff0c;与triplet loss是很相似的。对anchor-positive pair&#xff0c;都只有一个negative sample。而且&#xff0c;N-pair loss&#xff08;N2时&#xff09;为triplet loss的平滑近似Softpl…...