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

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. 就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而…...

Kubernetes之Controller详解

本文尝试从Kubernetes Controller的种类、交互逻辑、最佳实践、伪代码示例及历史演进5个方面对其进行详细阐述&#xff0c;希望对您有所帮助&#xff01; 一、Kubernetes Controller种类 Kubernetes Controller Manager 是 Kubernetes 集群的核心组件之一&#xff0c;负责管理…...

openlayers性能优化——开启图层预加载、减少空白等待时间

使用切片图层时、地图拖拽会有空白图片&#xff0c;为了减少空白等待时间&#xff0c;我们可以开始图层预加载。 const map_top new Map({layers: [new TileLayer({preload:Infinity, //预加载source: new StadiaMaps({layer: "outdoors",}),}),],target: "ma…...

BlockingQueue详解(含动画演示)

目录 BlockingQueue详解0、BlockingQueue简介BlockingQueue接口中方法注释BlockingQueue的实现&#xff0c;总结计划 1、ArrayBlockingQueue简介2、ArrayBlockingQueue的继承体系3、ArrayBlockingQueue的构造方法①、 ArrayBlockingQueue(int capacity)②、ArrayBlockingQueue(…...

wordpress商用付费主题与免费主题的区别

WordPress免费主题与WordPress付费主题&#xff0c;都可以用&#xff0c;但存在非常大的差别。从直观的感受&#xff0c;简单地说就是&#xff0c;WordPress免费主题能用&#xff0c;WordPress付费主题好用。如果涉及到其它的方面&#xff0c;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&#xff0c;以及本地或远程 MySQL 服务器多连线&#xff0c;使用者可浏览数据库、建立和删除数据库、编辑数据、建立或执行 SQL queries、管理使用者权限&#xff08;安全设定&#xff09;、将数据库备份/复原、汇入/汇出数据&…...

弱监督学习

弱监督学习&#xff08;Weak Supervision&#xff09;是一种利用不完全、不精确或噪声数据进行模型训练的方法。以下是一些常用的弱监督方法及其原理&#xff1a; 1. 数据增强&#xff08;Data Augmentation&#xff09; 原理&#xff1a; 数据增强是一种通过增加训练数据的多…...

代码随想录算法训练营第五十天|LeetCode1143 最长公共子序列、LeetCode1035 不相交的线、LeetCode53 最大子数组和

题1&#xff1a; 指路&#xff1a;1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 思路与代码&#xff1a; 类似于最长重复子数组&#xff0c;我们依旧定义一个二维数组dp[i][j]&#xff0c;其含义为从0到以i-1结尾的nums1数组和从0到j-1结尾的nums2数组的最…...

百日筑基第三天-SOA初步了解

百日筑基第三天-SOA初步了解 SOA&#xff08;Service-Oriented Architecture&#xff0c;面向服务的架构&#xff09;是一种软件设计原则&#xff0c;它倡导将应用程序分解为独立的服务单元&#xff0c;这些服务通过定义良好的接口相互通信&#xff0c;以实现业务功能。而RPC&…...

「2024中国数据要素产业图谱1.0版」重磅发布,景联文科技凭借高质量数据采集服务入选!

近日&#xff0c;景联文科技入选数据猿和上海大数据联盟发布的《2024中国数据要素产业图谱1.0版》数据采集服务板块。 景联文科技是专业数据服务公司&#xff0c;提供从数据采集、清洗、标注的全流程数据解决方案&#xff0c;协助人工智能企业解决整个AI链条中数据采集和数据标…...

条码二维码读取设备在医疗设备自助服务的重要性

医疗数字信息化建设的深入推进&#xff0c;医疗设备自助服务系统已成为医疗服务领域的一大趋势&#xff0c;条码二维码读取设备作为自助设备的重要组成部分&#xff0c;通过快速、准确地读取条形码二维码信息&#xff0c;不公提升了医疗服务效率&#xff0c;还为患者提供了更加…...

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

文章前提&#xff1a; 了解WMS基本作用了解window的概念&#xff0c;phoneWindow&#xff0c;rootViewImpl了解view的事件分发 开始&#xff1a; 讲三件事情&#xff1a; window的创建&#xff0c;更新焦点的更新事件的分发 Window的创建&#xff0c;更新&#xff1a; wi…...

Hive分区和分桶

分区&#xff1a; 根据某一列进行进行划分存储&#xff0c;常用的有时间分区&#xff1b; 查询数据时只需要扫描特定的分区数据&#xff0c;不需要全盘扫描&#xff0c;节省时间, 方便数据归档和清理 创建分区表 create table table_name( col1 int, col2 string ) partition …...

GPT-5的到来~

IT之家6月22日消息,在美国达特茅斯工程学院周四公布的采访中,OpenAI首席技术官米拉穆拉蒂被问及GPT-5是否会在明年发布,给出了肯定答案并表示将在一年半后发布。此外,穆拉蒂在采访中还把GPT-4到GPT-5的飞跃描述为高中生到博士生的成长。“像 GPT-4 这样的系统则更像是聪明的…...

责任链模式(设计模式)

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为设计模式&#xff0c;它允许多个对象有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合。将这些对象连成一条链&#xff0c;并沿着这条链传递请求&#xff0c;直到有一个对象处理…...

计算机图形学入门20:加速光线追踪

1.前言 前文说了Whitted-style光线追踪技术的原理以及光线与平面的交点计算方式&#xff0c;对于现在应用最广的Polygon Mesh显式曲面来说&#xff0c;一个复杂场景中的多边形面总数可能达到千万甚至亿万以上&#xff0c;如果每个像素发射光线都和场景中每个平面进行求交点计算…...

sys.stdin对象——实现标准输入

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 sys.stdin是一个标准化输入对象&#xff0c;可以连续输入或读入文件所有内容&#xff0c;不结束&#xff0c;不能直接使用。输入完成后&am…...

嵌入式项目分享| 终极智能手表,全过程+全开源分享

这是一个非常完整的智能手表开源项目,功能齐全,且资料开源,如果你是:自己平时喜欢diy的工程师,想要提升开发技能的学生,马上要做毕设的大四学生,这个手表很值得一做,别错过了~~ 所有开源的资料以及原文链接见文末。 先来看下这个手表的功能: 首先,是一个可以佩戴的手…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...