STL——vector

news2025/1/18 16:55:03

一、标准库中的vector

1.vector文档介绍

(1)vector是表示可变大小数组的序列容器。

(2)像数组一样,vector也采用连续存储空间来存储元素,也就意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是也有区别,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

(3)本质讲,vector使用动态分配数组来存储它的元素,当新元素插入的时候,这个数组需要被重新分配大小为了增加存储空间。其方法是,分配一个新的数组,然后将全部元素移到这个数组内。就时间而言,这是一个相对代价较高的任务,因为每当一个新的元素插入到容器的时候,vector并不会每次都重新分配大小。

(4)vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成。

(5)因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。

(6)与其他动态序列容器相比,vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效,对于其他不在末尾的删除和插入操作,效率更低。

2.vector的使用

2.1 vector的定义

2.2 vector iterator的使用

2.3  vector空间增长问题

(1)capacity的代码在vs和g++下的实现是不同的,vs下是PJ版的STL,capacity是按照1.5倍增长,而g++是SGI版的STL,是按照2倍增长。

(2)reserve只负责开辟空间,如果确定知道需要使用多少空间,reserve可以缓解vector扩容的代价缺陷问题。reserve期望开辟的空间大小只有比原空间大的情况下,才会真的去开辟空间进行扩容。

(3)resize在开辟空间的同时,还会进行初始化,影响size大小。

2.4vector的增删查改

3.vector迭代器失效问题★

3.1 什么是迭代器失效

        迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是指针,或者是对指针进行了封装。

        因此迭代器失效,实际就是迭代器底层对应指针失效,即所指向的空间非法(越界,或空间已经被释放)。

        后果就是,若继续使用已经失效的迭代器,程序就很可能会崩溃。

3.2 可能导致迭代器失效的操作

(1)会引起底层空间改变的操作,都有可能会引起迭代器失效

        如:resize、reserve、insert、push_back等。

(2)指定位置的删除操作--erase

        erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上迭代器不会失效,但是如果pos刚好是最后一个元素,删除之后pos刚好就是end的位置,而end位置是没有元素的,那么pos位置的迭代器就失效了。

3.2 如何避免

        在使用前,对迭代器重新赋值即可。

二、模拟实现vector

1.实现接口

1.1默认成员函数

vector();
vector(int n, const T& val = T());
template<class Iterator>
vector(Iterator start, Iterator end);
vector(const vector<T>& v);

vector<T>& operator=(vector<T> v);
~vector();

1.2迭代器相关

typedef T* iterator;
iterator begin();
iterator end();
iterator rbegin();
iterator rend();

1.3容量相关

size_t size() const ;
size_t capacity() const ;
bool empty() const;
void resize(size_t new_size, const T& val = T()) ;
void reserve(size_t new_capacity) ;

1.4元素访问相关

T& front() ;
const T& front() const;
T& back();
const T& back() const ;
T& operator[](size_t index);
const T& operator[](size_t index) const ;

1.5元素修改相关

void push_back(const T& val) ;
void pop_back() ;
iterator insert(iterator pos, const T& val) ;
iterator erase(iterator pos) ;
void clear() ;
void swap(vector<T>& v);

1.6私有成员

iterator _start;//指向数据块的初始位置
iterator _end;//指向有效数据的末尾
iterator _endofcapacity;//指向存储容量的末尾

2.代码实现

#include <iostream>
#include <assert.h>
#include <string>
//#include <vector>
using namespace std;

namespace MyVector {
	template<class T>
	class vector {
	public:
		//vector的迭代器是原生态的指针
		typedef T* iterator;
		typedef const T* const_iterator;

		/*----------类的默认成员函数----------*/
		//构造函数
		vector() 
			:_start(nullptr)
			,_end(nullptr)
			,_endofcapacity(nullptr)
		{}
		vector(int n, const T& val = T()) 
			:_start(new T[n])
			,_end(_start + n)
			,_endofcapacity(_start + n)
		{
			for (int i = 0; i < n; ++i) {
				_start[i] = val;
			}
		}
		template<class Iterator>
		vector(Iterator start, Iterator end) {
			//注意,求区间长度不能直接用end-start
			//因为有可能不是连续空间,比如list
			//获取区间长度
			size_t size = 0;
			Iterator it = start;
			while (it != end) {
				++it;
				++size;
			}
			//开辟空间,拷贝元素
			_start = new T[size];
			_end = _start;
			while (start != end) {
				*_end = *start;
				++_end;
				++start;
			}
			_endofcapacity = _end;
		}
		
		//拷贝构造
		vector(const vector<T>& v)
			:_start(new T[v.size()])
		{
			size_t size = v.size();
			for (size_t i = 0; i < size; ++i) {
				_start[i] = v[i];
			}
			_end = _start + size;
			_endofcapacity = _end;
		}
		//赋值运算符重载
		vector<T>& operator=(vector<T> v) {
			swap(v);
			return *this;
		}

		//析构函数
		~vector() {
			if (_start) {
				delete[] _start;
				_start = nullptr;
				_end = nullptr;
				_endofcapacity = nullptr;
			}
		}

		/*----------迭代器----------*/
		iterator begin() {
			return _start;
		}
		iterator end() {
			return _end;
		}
		iterator rbegin() {
			return _end;
		}
		iterator rend() {
			return _start;
		}

		/*----------容量相关----------*/
		size_t size() const {
			return _end - _start;
		}
		size_t capacity() const {
			return _endofcapacity - _start;
		}
		bool empty() const {
			return _start == _end;
		}
		void resize(size_t new_size, const T& val = T()) {
			size_t old_size = size();
			if (new_size <= old_size) {
				_end = _start + new_size;
			}
			else {
				size_t old_capacity = capacity();
				if (new_size > old_capacity) {//需要扩容
					reserve(new_size);
				}
				//为多出的空间放置val
				while (_end != _endofcapacity) {
					*_end = val;
					++_end;
				}
			}
		}
		void reserve(size_t new_capacity) {//扩容
			size_t old_capacity = capacity();
			size_t size = this->size();
			if (new_capacity > old_capacity) {
				//申请空间
				T* temp = new T[new_capacity];
				if (temp) {
					//拷贝元素
					//memcpy(temp, _start, sizeof(T) * size);//浅拷贝
					for (size_t i = 0; i < this->size(); ++i) {
						temp[i] = _start[i];
					}
					//释放原空间
					delete[] _start;
					_start = temp;
					_end = _start + size;
					_endofcapacity = _start + new_capacity;
				}
			}
		}

		/*----------元素访问----------*/
		T& front() {
			return *_start;
		}
		const T& front() const {
			return *_start;
		}
		T& back() {
			return *(_end - 1);
		}
		const T& back() const {
			return *(_end - 1);
		}
		T& operator[](size_t index) {
			assert(index < size());
			return _start[index];
		}
		const T& operator[](size_t index) const {
			assert(index < size());
			return _start[index];
		}

		/*----------元素修改----------*/
		void push_back(const T& val) {
			if (_end == _endofcapacity) {//需要扩容
				size_t size = this->size();
				if (size == 0) size = 1;//防止对0两倍扩容还是0
				reserve(size * 2);
			}
			*_end = val;
			++_end;
		}
		void pop_back() {
			if (empty()) return;
			--_end;
		}
		iterator insert(iterator pos, const T& val) {
			if (pos < _start || pos > _end) assert(0);
			if (_end == _endofcapacity) {//需要扩容
				size_t len = pos - _start;//记录pos距离开头的长度

				size_t size = this->size();
				if (size == 0) size = 1;//防止对0两倍扩容还是0
				reserve(size * 2);

				pos = _start + len;//发生扩容后,pos迭代器失效,需要重新赋值pos
			}
			//搬移元素
			iterator it = _end;
			while (it != pos) {
				*it = *(it - 1);
				--it;
			}
			//放置插入元素
			*it = val;
			_end++;
			return pos;
		}
		iterator erase(iterator pos) {//删除
			if (pos < _start || pos >= _end) assert(0);

			iterator it = pos;
			while (it != _end - 1) {
				*it = *(it + 1);
				++it;
			}
			_end--;
			return pos;
		}
		void clear() {
			_end = _start;
		}
		void swap(vector<T>& v) {
			std::swap(_start, v._start);
			std::swap(_end, v._end);
			std::swap(_endofcapacity, v._endofcapacity);
		}
	private: 
		iterator _start;//指向数据块的初始位置
		iterator _end;//指向有效数据的末尾
		iterator _endofcapacity;//指向存储容量的末尾
	};
}

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

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

相关文章

深度:用10000字总结了嵌入式C语言必学知识点

导读&#xff1a;怎么做好嵌入式&#xff1f;相信这个问题无论问谁你都会得到一句学好C语言&#xff01;今天推荐一篇大佬写的嵌入式C语言知识点总结&#xff0c;非常值得一读。 目录 1 关键字 2 数据类型 3 内存管理和存储架构 4 指针和数组 5 结构类型和对齐 6 预处理…

RDC 2022纪念版开发板-D1S在RT-Smart运行

开发环境 软件 ubuntu20.04VMware Workstation 硬件 RDC2022纪念版开发板全志D1s芯片 材料下载 首先打开虚拟机&#xff0c;创建一个目录存放本次测试的代码&#xff0c;然后克隆RT-Smart用户态代码。 git clone https://github.com/RT-Thread/userapps.git在userapps目…

SMB2协议特性之oplock与lease(下

前期回顾上篇文章我们介绍了oplock/lease的相关概念及其基本工作原理&#xff0c;由于间隔时间较长&#xff0c;忘记的读者可以先去回顾一下。本篇文章带大家了解一下&#xff0c;在实际场景中&#xff0c;oplock/lease是如何工作的。实际场景分析在一些警匪影视剧中&#xff0…

PCI驱动程序框架

PCI驱动程序框架 文章目录PCI驱动程序框架参考资料&#xff1a;一、 PCI驱动框架二、 RK3399驱动致谢参考资料&#xff1a; 《PCI Express Technology 3.0》&#xff0c;Mike Jackson, Ravi Budruk; MindShare, Inc.《PCIe扫盲系列博文》&#xff0c;作者Felix&#xff0c;这是…

【NS2】打印c++函数名字/bash将echo赋值给变量

需求&#xff1a;将tcl在c调用的路由算法名字&#xff08;函数名&#xff09;输出&#xff0c;并作为变量赋值给文件名字&#xff0c;但就怎么将函数名字打印出来就思考了很久&#xff0c;并尝试了其他网站“在shell脚本使用tcl变量、如何在bash脚本打印tcl变量、NS2&#xff0…

【实际开发12】- 经验 experience

目录 1. 经验 experience 1. 无多大价值 , 停留数据展示层面 2. 保证数据一致性问题 3. 新增时 , 可先关注核心基础数据 ( 复杂数据以修改形式完善 ) 4. 新增 / 修改 ( 幂等性处理 ) 5. 增 / 删 / 改 添加日志 , 查询无需日志 6. 需要对接多模块的通用字段设计 : String…

什么是CRM系统 企业如何选择合适的CRM系统

在如今市场竞争激烈情况下&#xff0c;企业更加注重客户的数据和管理&#xff0c;因此逐渐形成了“以客户为核心”的理念。而借助CRM系统管理客户数据已然成为一种趋势。 选择一款适合企业的CRM系统可以帮助企业实现更多的价值。但一些企业在初期根本不了解什么是CRM系统&…

Hadoop安装(一) --- JDK安装

目录 1.安装虚拟机 2.关防火墙 3.修改网络配置文件 4.重启网络服务 5.连接shell 6.安装vim工具 7.免密登陆 8. 开启远程免密登录配置 9.远程登录 10.同步时间 10.1.安装ntpdate 10.2.定时更新时间 10.3.启动定时任务 10.4.查看状态 11.修改计算机名 12.配置ho…

数据仓库的架构以及传统数据库与数据仓库的区别

一、数据仓库的分层架构 数据仓库的数据来源于不同的源数据&#xff0c;并提供多样的数据应用&#xff0c;数据自下而上流入数据仓库后向上层开放应用&#xff0c;而数据仓库只是中间集成化数据管理的一个平台。 1&#xff0c;源数据层&#xff08;ODS&#xff09; 操作性数…

袁树雄和杨语莲究竟什么关系 ,《早安隆回》走红后又是《汉川》

自从《早安隆回》火爆全网后&#xff0c;歌迷们就有一种担心&#xff0c;不知道这首好听的歌曲&#xff0c;究竟还能再够火爆多久。歌迷们的担心也不无道理&#xff0c;毕竟花无百日红&#xff0c;人无千般好&#xff0c;《早安隆回》就是再好听&#xff0c;也不可能红一辈子吧…

windows搭建go语言开发环境

1.下载Go语言开发包可以在Go语言官网 ( https://golang.google.cn/dl/ )下载Windows 系统下的Go语言开发包&#xff0c;如下图所示。这里我下载的是 64位的开发包&#xff0c;如果读者的电脑是 32 位系统的话&#xff0c;则需要下载 32 位的开发包&#xff0c;在上图所示页面中…

Fiddler手机抓包

手机抓包软件Fiddler 下载地址以及下载流程 Fiddler 下载地址&#xff1a;https://www.telerik.com/download/fiddler 下载后直接一键安装即可 重要的注意项卸载最前面 pc和手机需要在同一个局域网&#xff0c;也就是同一个wifi 配置 Fiddler界面的简单介绍 pc端Fildde…

Windows Server 2022 Install Veeam ONE 12

借助有关 Veeam Backup & Replication™ 和 Veeam Agents 及 VMware vSphere、Microsoft Hyper-V 和 Nutanix AHV 的洞察&#xff0c;Veeam ONE™ 可通过交互式工具和智能学习提供深度智能监控、报告和自动化功能&#xff0c;帮助客户发现问题并前瞻性地解决问题。 Veeam O…

CUDA编程之CUDA流

文章目录前言CUDA流在默认流中重叠主机与设备用非默认CUDA流重叠多个核函数的执行重叠多个核函数的例子用非默认CUDA流重叠核函数的执行与数据传递不可分页主机内存与异步的数据传输函数总结参考前言 CUDA程序的并行层次主要有两个&#xff0c;一个是核函数内部的并行&#xff…

C++面向对象——C++ 重载运算符和重载函数

C面向对象——C 重载运算符和重载函数C 重载运算符和重载函数C 中的函数重载C 中的运算符重载运算符重载实例C 一元运算符重载C 二元运算符重载C 关系运算符重载C 和 -- 运算符重载C 赋值运算符重载C 函数调用运算符 () 重载C 下标运算符 [] 重载C 类成员访问运算符 -> 重载…

三、进程通信

一、基础知识数据传输一个进程将他的数据发送给另一个进程资源共享多个进程间共享同样的资源通知时间一个进程向另一个进程发送消息&#xff0c;通知他们发生了某种事情通信方式&#xff1a;管道和有名管道信号signal消息队列共享内存信号量套接字二、管道&#xff1a;无名管道…

c++11 标准模板(STL)(std::multiset)(六)

定义于头文件 <set> template< class Key, class Compare std::less<Key>, class Allocator std::allocator<Key> > class multiset;(1)namespace pmr { template <class Key, class Compare std::less<Key>> usi…

基于python Django 餐馆点菜管理系统

问题描述&#xff1a; 随着网络的迅速发展&#xff0c;越来越多的人开始接受甚至时依赖了网络营业的这种交易形式&#xff0c;传统的点菜模式不仅浪费时间&#xff0c;效率低下&#xff0c;而且特别耗费成本与人力&#xff0c;因此不少商家开始使用网上点菜系统。网上点菜系统是…

皮尔森相关系数(Pearson correlation coefficient)

最近在看脑机接口的网络&#xff0c;看到有使用通道的皮尔森相关系数作为特征的方法&#xff0c;这里记录一下皮尔森相关系数的学习内容&#xff0c;方便以后查阅。 皮尔森相关系数(Pearson correlation coefficient&#xff09;相关系数简单相关系数复相关系数典型相关系数参考…

【MySQL】MySQL中的数学函数有哪些?

数学函数MySQL函数简介数学函数1.绝对值函数ABS&#xff08;x&#xff09;和返回圆周率的函数PI&#xff08;&#xff09;2.平方根函数SQRT&#xff08;x&#xff09;和求余函数MOD&#xff08;x&#xff0c;y&#xff09;3.获取整数的函数CEIL&#xff08;x&#xff09;、CEIL…