vector概述
vector是一个能够支持任何类型的容器,本身为一个可以动态增长的数组。
1、vector基本数据结构
STL中所有的容器都包括三部分:
- 迭代器,遍历容器的元素,控制容器空间的边界和元素移动。
- 构造函数,满足容器多种多样的初始化。
- 属性获取,比如begin(),end()等。
template <class T, class Alloc = alloc>
class vector {
public:
// 定义 vector 自身的嵌套型别
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
// 定义迭代器, 这里就只是一个普通的指针
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
...
protected:
typedef simple_alloc<value_type, Alloc> data_allocator; // 设置其空间配置器
iterator start; // 当前使用空间的头
iterator finish; // 当前使用空间的尾
iterator end_of_storage; // 当前可用空间的尾
...
};
因为 vector 需要表示用户操作的当前数据的起始地址,结束地址,还需要其真正的最大地址。所以总共需要 3 个迭代器,分别来指向数据的头(start),数据的尾(finish),数组的尾(end_of_storage)。
2、构造函数
vector是一种class template, 并不需要手动的释放内存,生命周期结束后就自动调用析构从而释放调用空间。
void deallocate() {
if (start)
data_allocator::deallocate(start, end_of_storage - start);
}
// 调用析构函数并释放内存
~vector() {
destroy(start, finish);
deallocate();
}
3、属性获取
比如返回 vector 的开始和结尾,返回最后一个元素,返回当前元素个数,元素容量,是否为空等。这里需要注意的是因为 end() 返回的是 finish,而 finish 是指向最后一个元素的后一个位置的指针,所以使用 end() 的时候要注意。
public:
// 获取数据的开始以及结束位置的指针. 记住这里返回的是迭代器, 也就是 vector 迭代器就是该类型的指针.
iterator begin() { return start; }
iterator end() { return finish; }
reference front() { return *begin(); } // 获取值
reference back() { return *(end() - 1); }
...
size_type size() const { return size_type(end() - begin()); } // 数组元素的个数
size_type max_size() const { return size_type(-1) / sizeof(T); } // 最大能存储的元素个数
size_type capacity() const { return size_type(end_of_storage - begin()); } // 数组的实际大小
bool empty() const { return begin() == end(); }
//判断 vector 是否为空, 并不是比较元素为 0,是直接比较头尾指针。
4、push和pop操作
vector 的 push 和 pop 操作都只是对尾进行操作, 这里说的尾部是指数据的尾部。当调用 push_back 插入新元素的时候,首先会检查是否有备用空间,如果有就直接在备用空间上构造元素,并调整迭代器 finish。
如果没有备用空间,就扩充空间(重新配置-移动数据-释放原空间),这里实际是调用了另外一个函数:insert_aux 函数。
上图中显示push_back这个函数判断了一次 finish != end_of_storage 这是原因是因为 insert_aux 函数可能还被其他函数调用。
在else 分支进行vector 的动态扩容机制:如果原空间大小为 0 则分配 1 个元素,如果大于0则分配原空间两倍的新空间,然后把数据拷贝过去。
5、pop 元素:
从尾端删除一个元素。
void pop_back()
{ // erase element at end
erase(end() - 1);
}
6、erase 删除元素
erase 函数清除指定位置的元素, 其重载函数用于清除一个范围内的所有元素。实际上就是将删除元素后面所有元素往前移动,对于 vector 来说删除元素的操作开销很大,所以说 vector 它不适合频繁的删除操作,因为它本身是一个数组。示意图如下所示:
清除指定范围内的元素,首先将 finish 迭代器后面的元素拷贝回去,然后返回拷贝完成的尾部迭代器,最后再销毁之后的元素。
删除指定位置的元素就是实际就是将指定位置后面的所有元素向前移动, 最后析构掉最后一个元素。
7、insert 元素
- 插入点之后的现有元素个数 > 新增元素个数
- 插入点之后的现有元素个数 <= 新增元素个数
- 如果备用空间不足
注意:
vector有一个迭代失效问题。所谓迭代失效时由于元素空间重新分配导致之前迭代器访问的元素不存在了,总体有两种情况:
- 由于插入元素,使得容器元素整体迁移导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。
- 由于删除元素,使得某些元素次序发生改变导致原本指向某元素的迭代器不再指向期望指向的元素。
全局函数说明:
- copy(a,b,c):将(a,b)之间的元素拷贝到(c,c-(b-a))位置。
- uninitialized_copy(first, last, result):具体作用是将 [first,last)内的元素拷贝到 result 从前往后拷贝。
- copy_backward(first, last, result):将 [first,last)内的元素拷贝到 result 从后往前拷贝。
8、vector总结
- vector的成员函数都不做边界检查(at方法会抛异常),使用者要自己确保迭代器和索引值的合法性。
- 优点
- 在内存中占用一块联系的内存空间存储数据,可以像数组一样操作,并且支持动态扩容。
- 正因如此,其元素可以随机访问,支持下标和vector.at()操作。
- 节省空间。
- 缺点
- 由于其顺序存储的特性,vector插入、删除操作的时间复杂度是Q(n)。
- 只能在末端进行pop和push操作。
- 当动态长度超过默认分配大小后,需要整体重新分配、拷贝和释放空间。
vector概述的更多相关文章
- STL源码剖析读书笔记之vector
STL源码剖析读书笔记之vector 1.vector概述 vector是一种序列式容器,我的理解是vector就像数组.但是数组有一个很大的问题就是当我们分配 一个一定大小的数组的时候,起初也许我们 ...
- 带你深入理解STL之Vector容器
C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. ST ...
- vector源码1(参考STL源码--侯捷):源码
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- Java集合框架之Vector浅析
Java集合框架之Vector浅析 一.Vector概述: 位于java.util包下的Vector是Java集合框架的重要一员,虽然没有ArrayList那么的常用,但是我们还要对其做相关学习: 1 ...
- java源码--Vector和Stack
一.Vector简介 1.1.Vector概述 通过API中可以知道: 1)Vector是一个可变化长度的数组 2)Vector增加长度通过的是capacity和capacityIncrement这两 ...
- 【c++】标准模板库STL入门简介与常见用法
一.STL简介 1.什么是STL STL(Standard Template Library)标准模板库,主要由容器.迭代器.算法.函数对象.内存分配器和适配器六大部分组成.STL已是标准C++的一部 ...
- STL源码剖析读书笔记--第四章--序列式容器
1.什么是序列式容器?什么是关联式容器? 书上给出的解释是,序列式容器中的元素是可序的(可理解为可以按序索引,不管这个索引是像数组一样的随机索引,还是像链表一样的顺序索引),但是元素值在索引顺序的方向 ...
- Java集合源码分析(三)Vevtor和Stack
前言 前面写了一篇关于的是LinkedList的除了它的数据结构稍微有一点复杂之外,其他的都很好理解的.这一篇讲的可能大家在开发中很少去用到.但是有的时候也可能是会用到的! 注意在学习这一篇之前,需要 ...
- STL——序列式容器
一.容器概述与分类 1. STL容器即是将运用最广的一些数据结构实现出来.常用的数据结构有array, list, tree, stack, queue, hash table, set, map…… ...
随机推荐
- Saving Beans(hud3037)
Saving Beans Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- Codeforces 339B:Xenia and Ringroad(水题)
time limit per test : 2 seconds memory limit per test : 256 megabytes input : standard input output ...
- SpringMVC 五大组件
DispatcherServlet HandleMapping Controller ModeAndView ViewResolver 1.DispatcherServlet 这个控件是SpringM ...
- 强强联袂!腾讯云TDSQL与国双战略签约,锚定国产数据库巨大市场
日前,腾讯云计算(北京)有限责任公司与北京国双科技有限公司签署了<国产数据库产品战略合作协议>,双方将在数据库技术方面展开深度合作,通过分布式交易型数据库的联合研发.产品服务体系建设.品牌 ...
- Java Web程序设计笔记 • 【目录】
章节 内容 实践练习 Java Web程序设计作业目录(作业笔记) 第1章 Java Web程序设计笔记 • [第1章 Web应用程序] 第2章 Java Web程序设计笔记 • [第2章 JSP基础 ...
- linux 设置开机自动启动应用
作为一个开发,项目现在一般都是部署在虚拟机上的linux,数据库也是按照在l虚拟机上的linux,一旦关机了,在开机程序都没打开,又要一个个去开,很麻烦,所以现在我现在使用supervisor去做一个 ...
- linux 之 导出远程oracle数据库表结构及数据
导出用户下所有表结构及数据 exp 用户名/密码@ip/数据库 file=文件路径/文件名.dmp owner='用户' 导出用户下所有表结构,不导出数据 exp 用户名/密码@ip/数据库 file ...
- hive 之 将excel数据导入hive中 : excel 转 txt
一.需求: 1.客户每月上传固定格式的excel文件到指定目录.每月上传的文件名只有结尾月份不同,如: 10月文件名: zhongdiangedan202010.xlsx , 11月文件名: zh ...
- 学习git&github
详细学习视频: 链接:https://pan.baidu.com/s/1Vub3YTo7uUUuGCJUCabBRQ 提取码:6q9x 一.git基本工作流程 我们先来理解下Git 工作区.暂存区和版 ...
- vi中使用鼠标右键插入时进入(insert)visual模式
使用vim插入外面复制的内容时,用右键点击后,并未将内容粘贴进去,而是进入了(insert)visual模式,解决方法:先shift+enter进入普通模式输入 set mouse-=a然后再i进入i ...