C++ Vector的模拟实现
vector的介绍
1. vector是表示可变大小数组的序列容器。
2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。
参考侯捷老师《STL源码刨析》这本书画的:

Vector的一些接口:
namespace MyVector
{template<class T>class vector{public:// Vector的迭代器是一个原生指针typedef T* iterator;typedef const T* const_iterator;iterator begin();iterator end();const_iterator cbegin() const;const_iterator cend() const; // 初始化vector();// 析构~vector();vector(int n, const T& value = T());vector(size_t n, const T& val = T());//类模板的成员函数可以是函数模板template<class InputIterator>vector(InputIterator first, InputIterator last);vector(const vector<T>& v);vector<T>& operator= (vector<T> v);size_t size() const;size_t capacity() const;void reserve(size_t n);void resize(size_t n, const T& value = T());T& operator[](size_t pos);const T& operator[](size_t pos)const;bool empty();void push_back(const T& x);void pop_back();void swap(vector<T>& v);iterator insert(iterator pos, const T& x);iterator erase(iterator pos);private:iterator _start = nullptr; // 指向数据块的开始iterator _finish = nullptr; // 指向有效数据的尾iterator _endOfStorage = nullptr;// 指向存储容量的尾};
}
iterator begin()
iterator begin(){return _start;}
iterator end()
iterator end(){return _finish;}
const_iterator cbegin()
const_iterator cbegin(){return _start;}
const_iterator cend() const
const_iterator cend() const{return _finish;}
四个比较简单的迭代器
vector()
vector():_start(nullptr),_finish(nullptr), _endOfStorage(nullptr){}
~vector()
~vector(){delete[] _start;_start = _finish = _endOfStorage;}
初始化与析构
//类模板的成员函数可以是函数模板template<class InputIterator> // InputIterator定义的一个迭代器类型vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _endOfStorage(nullptr){while (first != last){push_back(*first);++first;}}
vector<T>& operator= (vector<T> v)
vector<T>& operator= (vector<T> v){swap(v);return *this;}
// v1 = v3
size_t size() const
size_t size() const{return _finish - _start;}
// 有效数据的尾减去数据块的开始就是元素个数
size_t capacity() const
size_t capacity() const{return _endOfStorage - _start;}
// 开辟空间的容量
void reserve(size_t n)
void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t old_size = size();for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i]; // 深拷贝}delete[] _start;_start = tmp; // 老的_start已经失效,更新一下_finish = tmp + old_size;_endOfStorage = tmp + n;}}
void resize(size_t n, const T& value = T())
void resize(size_t n, const T& value = T()){if (n > size()) // 超过就扩容{reserve(n);while (_finish < _start + n){*_finish = value;++_finish;}}else{_finish = _start + n;}}
vector(const vector<T>& v)
vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}
// v2(v1) 用已经存在的 v1 去初始化 v2
T& operator[](size_t pos)
const T& operator[](size_t pos)const
T& operator[](size_t pos){assert(pos < size()); // 保证下标为有效数据return _start[pos];}const T& operator[](size_t pos)const{assert(pos < size());return _start[pos];}
iterator insert(iterator pos, const T& x)
iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endOfStorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());//如果扩容了要更新pospos = _start + len;}iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;--it;}*pos = x;++_finish;}
iterator erase(iterator pos)
iterator erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;--it;}--_finish;return pos;}
vector(int n, const T& value = T())
vector(int n, const T& value = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(value);}}
vector(size_t n, const T& val = T())
vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}
bool empty()
bool empty(){return _start == _finish;}
void push_back(const T& x)
void push_back(const T& x){insert(end(), x);}
void pop_back()
void pop_back(){erase(end() - 1);}
void swap(vector<T>& v)
void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}
完整代码:
#pragma once#include <assert.h>namespace bit
{template<class T>class vector{public:// Vector的迭代器是一个原生指针typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator cbegin(){return _start;}const_iterator cend() const{return _finish;}// construct and destroyvector():_start(nullptr),_finish(nullptr), _endOfStorage(nullptr){}vector(int n, const T& value = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(value);}}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}//类模板的成员函数可以是函数模板template<class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _endOfStorage(nullptr){while (first != last){push_back(*first);++first;}}vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}vector<T>& operator= (vector<T> v){swap(v);return *this;}~vector(){delete[] _start;_start = _finish = _endOfStorage;}size_t size() const{return _finish - _start;}size_t capacity() const{return _endOfStorage - _start;}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t old_size = size();for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = tmp + old_size;_endOfStorage = tmp + n;}}void resize(size_t n, const T& value = T()){if (n > size()){reserve(n);while (_finish < _start + n){*_finish = value;++_finish;}}else{_finish = _start + n;}}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos)const{assert(pos < size());return _start[pos];}bool empty(){return _start == _finish;}void push_back(const T& x){insert(end(), x);}void pop_back(){erase(end() - 1);}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endOfStorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());//如果扩容了要更新pospos = _start + len;}iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;--it;}*pos = x;++_finish;}iterator erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;--it;}--_finish;return pos;}private:iterator _start = nullptr; // 指向数据块的开始iterator _finish = nullptr; // 指向有效数据的尾iterator _endOfStorage = nullptr;// 指向存储容量的尾};}
测试代码:
#include <iostream>
#include<algorithm>
#include<vector>#include "Vector.h"using namespace std;int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);cout << v.size() << endl;cout << v.capacity() << endl;for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;v.reserve(30);cout << v.capacity() << endl;vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;vector<int> v1(v);v1.push_back(100);v1.push_back(200);v1.pop_back();for (auto e : v1){cout << e << " ";}
}
相关文章:
C++ Vector的模拟实现
vector的介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而…...
Kubernetes之Controller详解
本文尝试从Kubernetes Controller的种类、交互逻辑、最佳实践、伪代码示例及历史演进5个方面对其进行详细阐述,希望对您有所帮助! 一、Kubernetes Controller种类 Kubernetes Controller Manager 是 Kubernetes 集群的核心组件之一,负责管理…...
openlayers性能优化——开启图层预加载、减少空白等待时间
使用切片图层时、地图拖拽会有空白图片,为了减少空白等待时间,我们可以开始图层预加载。 const map_top new Map({layers: [new TileLayer({preload:Infinity, //预加载source: new StadiaMaps({layer: "outdoors",}),}),],target: "ma…...
BlockingQueue详解(含动画演示)
目录 BlockingQueue详解0、BlockingQueue简介BlockingQueue接口中方法注释BlockingQueue的实现,总结计划 1、ArrayBlockingQueue简介2、ArrayBlockingQueue的继承体系3、ArrayBlockingQueue的构造方法①、 ArrayBlockingQueue(int capacity)②、ArrayBlockingQueue(…...
wordpress商用付费主题与免费主题的区别
WordPress免费主题与WordPress付费主题,都可以用,但存在非常大的差别。从直观的感受,简单地说就是,WordPress免费主题能用,WordPress付费主题好用。如果涉及到其它的方面,WordPress商用付费主题与免费主题之…...
【ARM Trace32(劳特巴赫) 使用介绍 2.7 -- bat 脚本传参数给 trace32 cmm 脚本】
请阅读【Trace32 ARM 专栏导读】 文章目录 bat 脚本传参数给 trace32脚本可变参数传入CMM 脚本接收参数运行BAT脚本bat 脚本传参数给 trace32脚本 在使用 Trace32 的过程中,如果每次都是通过GUI 界面来操作,是习惯使用命令行工作的人所不能忍受的!!!,那么能不同通过脚本…...
NavicatforMySQL11.0软件下载-NavicatMySQL11最新版下载附件详细安装步骤
我们必须承认Navicat for MySQL 支援 Unicode,以及本地或远程 MySQL 服务器多连线,使用者可浏览数据库、建立和删除数据库、编辑数据、建立或执行 SQL queries、管理使用者权限(安全设定)、将数据库备份/复原、汇入/汇出数据&…...
弱监督学习
弱监督学习(Weak Supervision)是一种利用不完全、不精确或噪声数据进行模型训练的方法。以下是一些常用的弱监督方法及其原理: 1. 数据增强(Data Augmentation) 原理: 数据增强是一种通过增加训练数据的多…...
代码随想录算法训练营第五十天|LeetCode1143 最长公共子序列、LeetCode1035 不相交的线、LeetCode53 最大子数组和
题1: 指路:1143. 最长公共子序列 - 力扣(LeetCode) 思路与代码: 类似于最长重复子数组,我们依旧定义一个二维数组dp[i][j],其含义为从0到以i-1结尾的nums1数组和从0到j-1结尾的nums2数组的最…...
百日筑基第三天-SOA初步了解
百日筑基第三天-SOA初步了解 SOA(Service-Oriented Architecture,面向服务的架构)是一种软件设计原则,它倡导将应用程序分解为独立的服务单元,这些服务通过定义良好的接口相互通信,以实现业务功能。而RPC&…...
「2024中国数据要素产业图谱1.0版」重磅发布,景联文科技凭借高质量数据采集服务入选!
近日,景联文科技入选数据猿和上海大数据联盟发布的《2024中国数据要素产业图谱1.0版》数据采集服务板块。 景联文科技是专业数据服务公司,提供从数据采集、清洗、标注的全流程数据解决方案,协助人工智能企业解决整个AI链条中数据采集和数据标…...
条码二维码读取设备在医疗设备自助服务的重要性
医疗数字信息化建设的深入推进,医疗设备自助服务系统已成为医疗服务领域的一大趋势,条码二维码读取设备作为自助设备的重要组成部分,通过快速、准确地读取条形码二维码信息,不公提升了医疗服务效率,还为患者提供了更加…...
centos 7.8 安装sql server 2019
1.系统环境 centos 7.8 2.数据库安装文件准备 下载 SQL Server 2019 (15.x) Red Hat 存储库配置文件 sudo curl -o /etc/yum.repos.d/mssql-server.repo https://packages.microsoft.com/config/rhel/7/mssql-server-2019.repo 采用yum源进行不安装下载,这时yum 会自动检测…...
Android焦点机制结合WMS
文章前提: 了解WMS基本作用了解window的概念,phoneWindow,rootViewImpl了解view的事件分发 开始: 讲三件事情: window的创建,更新焦点的更新事件的分发 Window的创建,更新: wi…...
Hive分区和分桶
分区: 根据某一列进行进行划分存储,常用的有时间分区; 查询数据时只需要扫描特定的分区数据,不需要全盘扫描,节省时间, 方便数据归档和清理 创建分区表 create table table_name( col1 int, col2 string ) partition …...
GPT-5的到来~
IT之家6月22日消息,在美国达特茅斯工程学院周四公布的采访中,OpenAI首席技术官米拉穆拉蒂被问及GPT-5是否会在明年发布,给出了肯定答案并表示将在一年半后发布。此外,穆拉蒂在采访中还把GPT-4到GPT-5的飞跃描述为高中生到博士生的成长。“像 GPT-4 这样的系统则更像是聪明的…...
责任链模式(设计模式)
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许多个对象有机会处理请求,从而避免请求的发送者和接收者之间的耦合。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理…...
计算机图形学入门20:加速光线追踪
1.前言 前文说了Whitted-style光线追踪技术的原理以及光线与平面的交点计算方式,对于现在应用最广的Polygon Mesh显式曲面来说,一个复杂场景中的多边形面总数可能达到千万甚至亿万以上,如果每个像素发射光线都和场景中每个平面进行求交点计算…...
sys.stdin对象——实现标准输入
自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 sys.stdin是一个标准化输入对象,可以连续输入或读入文件所有内容,不结束,不能直接使用。输入完成后&am…...
嵌入式项目分享| 终极智能手表,全过程+全开源分享
这是一个非常完整的智能手表开源项目,功能齐全,且资料开源,如果你是:自己平时喜欢diy的工程师,想要提升开发技能的学生,马上要做毕设的大四学生,这个手表很值得一做,别错过了~~ 所有开源的资料以及原文链接见文末。 先来看下这个手表的功能: 首先,是一个可以佩戴的手…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...
[特殊字符] Spring Boot底层原理深度解析与高级面试题精析
一、Spring Boot底层原理详解 Spring Boot的核心设计哲学是约定优于配置和自动装配,通过简化传统Spring应用的初始化和配置流程,显著提升开发效率。其底层原理可拆解为以下核心机制: 自动装配(Auto-Configuration) 核…...
dvwa11——XSS(Reflected)
LOW 分析源码:无过滤 和上一关一样,这一关在输入框内输入,成功回显 <script>alert(relee);</script> MEDIUM 分析源码,是把<script>替换成了空格,但没有禁用大写 改大写即可,注意函数…...
调试快捷键 pycharm vscode
目录 调试快捷键 pycharm vscode 修改快捷键 方法 1:通过菜单打开 方法 2:用快捷键打开 调试快捷键 pycharm Resume Program F9 Step Over F8 两个离的比较近,比较方便,比vscode的好。 vscode Continue F5 改为F9 S…...
SAP学习笔记 - 开发24 - 前端Fiori开发 Filtering(过滤器),Sorting and Grouping(排序和分组)
上一章讲了SAP Fiori开发的表达式绑定,自定义格式化等内容。 SAP学习笔记 - 开发23 - 前端Fiori开发 Expression Binding(表达式绑定),Custom Formatters(自定义格式化)-CSDN博客 本章继续讲SAP Fiori开发…...
code-server安装使用,并配置frp反射域名访问
为什么使用 code-server是VSCode网页版开发软件,可以在浏览器访问编程,可以使用vscode中的插件。如果有自己的服务器,使用frp透传后,域名访问在线编程,使用方便,打开的服务端口不需要单独配置,可…...
Git 使用大全:从入门到精通
Git 是目前最流行的分布式版本控制系统,被广泛应用于软件开发中。本文将全面介绍 Git 的各种功能和使用方法,包含大量代码示例和实践建议。 文章目录 Git 基础概念版本控制系统Git 的特点Git 的三个区域Git 文件状态 Git 安装与配置安装 GitLinuxmacOSWi…...
