vector

0. vector的介绍

vector是用数组实现的、可变长度的顺序容器,本质是一种类模板。

template < class T, // 元素类型class Alloc = allocator<T> > // 空间配置器类型class vector; // 类模板声明

1. vector的接口

1.1 默认成员函数

接口声明 解释
vector() 默认构造
vecotr(size_type n, const_value_type& val=value_type()) 填充构造,填充n个元素
vector(InputIter first, InputIter last) 范围构造,迭代器区间初始化
vector(const vector& v) 拷贝构造
vector& operator=(const vector& x) 赋值重载

1.2 容量操作

容量操作 解释
size_type size() 元素个数
size_type capacity() 容量大小
size_type max_size() 最大能存储的元素个数(无意义)
void resize(size_type n, value_type val = value_type()); 增减有效元素个数
v.reserve(100);   // 扩容到100
v.resize(100, 1); // 有效元素个数变为100,新增元素初始化为1
v.resize(10);     // 有效元素个数变为10

由图可知,vs下vector按1.5倍增容。

1.3 访问操作

接口声明 解释
reference operator[](size_type n) 返回下标位置的引用
const_reference operator[] (size_type n) const
reference at(size_type n)
const_reference at (size_type n) const

[]重载和at的区别是,[]越界会断言报错,at是抛异常。

迭代器接口 解释
begin 起始位置的迭代器
end 末尾元素的下一个位置的迭代器
rbegin 反向起始位置的迭代器
rend 反向末尾元素的下一个位置的迭代器
cbegin,cend begin 和 end 的 const 版本

[]重载就已经能方便的访问 vector,但并不意味着放弃迭代器。大部分容器都支持迭代器访问,且迭代器使用简单规范统一。

STL 中容器的迭代器区间都是采用 [first,last)[first,last)[first,last) 左闭右开的方式。

//[]
for (size_t i = 0; i < v.size(); i++) {v1[i] += 1;
}//iterator
vector<int>::iterator it = v.begin();
while (it != v.end()) {cout << *it << " ";it++;
}for (auto e : v) {cout << e << " ";
}

1.4 修改操作

接口声明 解释
void push_back (const value_type& val) 尾插
void pop_back() 尾删
iterator insert (iterator pos, const value_type& val) 迭代器位置插入
void insert (iterator pos, size_type n, const value_type& val); 迭代器位置插入
void insert (iterator pos, InputIter first, InputIter last) 迭代器位置插入一段区间
iterator erase (iterator pos) 迭代器位置删除
iterator erase (iterator first, iterator last) 删除一段迭代器区间
void assign (size_type n, const value_type& val) 覆盖数据
v.insert(ret, 30);
v.insert(ret, 2, 30);
v.insert(ret, v2.begin(), v2.end());
v1.erase(pos);
v1.erase(v1.begin(), v1.end());
#include <algorithm>
// 查找接口
template <class InputIter, class T>InputIter find (InputIter first, InputIter last, const T& val);

2. vector的模拟实现

2.1 类的定义

template <class T, class Alloc = alloc>
class vector {public:typedef T* iterator;// ...
private:iterator start;iterator finish;ggggiterator end_of_storage;
}

这个结构和顺序表结构稍有不同,但本质是一样的。只是将容量和元素个数的变量用指向对应位置的迭代器代替。

class Seqlist {T* _a;            /* start */size_t _size;     /* finish - start */size_t _capacity; /* end_of_storage - start */
}

2.2 默认成员函数

//default constructor
vector(): _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{}
//fill constructor
vector(size_t n, const T& val = T()) // 引用临时对象可延长其声明周期: _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{resize(n, val);
}
//copy constructor
vector(const vector<T>& v): _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{_start = new T[v.capacity()];for (size_t i = 0; i < v.capacity(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();
}
//range constructor
template <class InputIterator>
vector(InputIterator first, InputIterator last) : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{while (first != last) {push_back(*first++);}
}
//destructor
~vector()
{delete[] _start;_start = _finish = _end_of_storage = nullptr;
}// 现代写法
//copy constructor
vector(const vector<T>& v) : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{vector<T> tmp(v.begin(), v.end());swap(tmp);
}
//operator=
vector<T>& operator=(vector<T> v)  /* pass by value */
{swap(v);return *this;
}

从范围构造可以看出类模板中的函数也可以是函数模板。

迭代器的分类

函数模板的模板参数要传迭代器区间时,命名是有规定的,范围构造中的InputIterator就是一种指定的迭代器类型。因容器的结构各有不同,迭代器分为五种类型:

迭代器类型 名称 解释 适用容器
input/output_iterator 输入/输出迭代器 只读迭代器只能读取,只写迭代器可以写入该位置的值 无实际容器
forward_iterator 向前迭代器 只能向前移动(++),允许在迭代器位置进行读写 forward_list
bidirectional_iterator 双向迭代器 可以双向移动(++,––),允许在迭代器位置进行读写 list, map, set
random_access_iterator 随机迭代器 支持指针运算,可移动(++,––)任意跳转(+,–)读写(*) deque,vector,string

可以看出,下方的迭代器类型是上方的父类,也就是说下方迭代器满足上方的所有要求

划分出不同的迭代器类型,是为了限制传入的迭代器,因为其必须满足要求才能完成接下来的函数。

函数如果指明迭代器类型为InputIterator,意思是满足输入迭代器的要求的迭代器都可以作此参数。故此处我们可以传入任意的迭代器。

一般底层是数组连续空间的容器,例如 vector, string 等都是随机迭代器。

像双向链表这样的非连续空间的容器是双向迭代器。

2.3 容量接口

memcpy 浅拷贝问题

vector<string> v;
v.push_back("11111111111111");
v.push_back("11111111111111");
v.push_back("11111111111111");
v.push_back("11111111111111");
v.push_back("11111111111111"); // 增容浅拷贝

出现问题是因为正好数组需要增容。模拟实现的reserve函数使用memcpy将原空间的内容按字节拷贝至新空间。

  1. 若 vector 存储的是内置类型,则浅拷贝没问题。
  2. 若 vector 存储的是自定义类型,浅拷贝使得新旧变量指向同一块空间。深拷贝调用拷贝构造或者赋值重载。

void reserve(size_t n)
{if (n > capacity()) {T* tmp = new T[n];size_t oldSize = size();if (_start) {//memcpy(tmp, _start, size() * sizeof(T)); // errfor (int i = 0; i < size(); i++) {tmp[i] = _start[i];//_start指向的空间存任意类型都能完成深拷贝}delete[] _sta rt;}_start = tmp;_finish = _start + oldSize;_end_of_storage = _start + n;}
}
void resize(size_t n, T val = T())
{if (n > size()){reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}
}

2.4 修改接口

iterator insert(iterator pos, const T& val)
{assert(_start <= pos && pos <= _finish); // 检查pos位置是否合法// 增容if (_finish == _end_of_storage) {size_t sz = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2); //增容会导致迭代器失效,迭代器位置陈旧pos = _start + sz; //增容后更新pos}// 后移 [pos,_finish)for (iterator end = _finish; end > pos; --end){*end = *(end - 1);}// 插入*pos = val;++_finish;return pos; //返回迭代器最新位置
}
  • 增容改变_start,但迭代器pos并没有跟着改变,仍然指向原空间,也就是迭代器失效。
  • 迭代器pos实参并没有改变仍然指向错误位置,故函数返回更新的pos
iterator erase(iterator pos)
{assert(_start <= pos && pos < _finish);for (iterator begin = pos + 1; begin < _finish; begin++){*(begin - 1) = *begin;}_finish--;return pos; //返回删除数据的下一个位置
}

  • erase 挪动数据后 pos 指向元素会发生变化,同样会导致迭代器失效。
  • 返回删除数据的下一个位置,通过返回值更新迭代器。

3. vector的oj题

题目 题解
只出现一次的数字 【简洁明了】只出现一次的数字 I
杨辉三角 【简洁明了】cpp 杨辉三角
删除有序数组中的重复项 【双指针 简单明了】数组去重
只出现一次的数字 II 【简单明了 注释】只出现一次的数字
只出现一次的数字 III 【详细解析】只出现一次的数字 系列 I II III
多数元素 【哈希 排序 投票】三种解法 简洁明了
连续子数组的最大和 【动归】连续子数组的最大和
电话号码的字母组合 【注释解析 回溯】电话号码字母组合

C++初阶:vector类相关推荐

  1. C++初阶 — vector

    目录 一.vector的介绍及使用 1. vector的介绍 2. vector的使用 2.1 vector的定义 2.2 vector iterator 的使用 2.3 vector 空间增长问题 ...

  2. 【C++初阶】类和对象(二)

    大家好我是沐曦希

  3. 学习笔记:C++初阶【C++入门、类和对象、C/C++内存管理、模板初阶、STL简介、string、vector、list、stack、queueu、模板进阶、C++的IO流】

    文章目录 前言 一.C++入门 1. C++关键字 2.命名空间 2.1 C语言缺点之一,没办法很好地解决命名冲突问题 2.2 C++提出了一个新语法--命名空间 2.2.1 命名空间概念 2.2.2 ...

  4. java 课后习题 Vector类的 初使用

    知识点: 1.Vector 类的使用 多类型数据的Vector类 2-addElement(obj); //添加元素 (int)Student.elementAt //把元素的值作为整型输出 Stud ...

  5. 【JAVA 第五章 】课后习题 Vector类的 初使用

    知识点: 1.Vector 类的使用 多类型数据的Vector类 2-addElement(obj); //添加元素 3. (int)Student.elementAt //把元素的值作为整型输出 4 ...

  6. R语言学习笔记——入门篇:第三章-图形初阶

    R语言 R语言学习笔记--入门篇:第三章-图形初阶 文章目录 R语言 一.使用图形 1.1.基础绘图函数:plot( ) 1.2.图形控制函数:dev( ) 补充--直方图函数:hist( ) 补充- ...

  7. 数据结构初阶(4)(OJ练习【判断链表中是否有环、返回链表入口点、删除链表中的所有重复出现的元素】、双向链表LinkedList【注意事项、构造方法、常用方法、模拟实现、遍历方法、顺序表和链表的区别)

    接上次博客:数据结构初阶(3)(链表:链表的基本概念.链表的类型.单向不带头非循环链表的实现.链表的相关OJ练习.链表的优缺点 )_di-Dora的博客-CSDN博客 目录 OJ练习 双向链表--Li ...

  8. C/C++内存管理模板初阶

    内存管理和模板初阶 1 内存管理 1.1 C/C++ 的内存分布 1.2 C 中动态内存管理方式 1.3 C++ 中动态内存管理方式 1.3.1 new/delete操作内置类型 1.3.2 new/ ...

  9. c++之模板初阶详解!

    c++之模板初阶详解 文章目录 c++之模板初阶详解 泛型编程 函数模板 函数模板概念 函数模板格式 模板的原理 函数模板的实例化 模板实例化的个数 对于同不同类型的传参! 如何处理这个问题呢? 关于 ...

最新文章

  1. mysql 电商项目(一)
  2. 如何将OutputStream转换为InputStream?
  3. jdk 版本和内部版本对应_JDK 14 Rampdown:内部版本27
  4. c++ 操作mysql_C++操作mysql方法总结(1)
  5. 使用Newtonsoft.Json格式化JSON文档
  6. 【英语学习】【WOTD】countermand 释义/词源/示例
  7. 安卓阵营最强Soc!骁龙898即将亮相:小米12系列本月底前后首发
  8. ubuntu安装php7-mysql,ubuntu上安装php7.0+nginx+mysql
  9. JQuery操作cookie插件
  10. Flash存储的故事
  11. web地图热力图理解
  12. 中国民营500强企业爬取数据展示
  13. NR Polar Code 四 译码1(SC: N=2,N=4)
  14. 【分享】北京社保查询API
  15. 批量jpg转png 批量png转jpg 批量jpg2png 批量png2jpg
  16. deepin网速慢 自己摸索 已解决
  17. OpenGL初学者入门——学习指南【共 9 篇文章】
  18. android 四方向摇杆源码,手游摇杆(一)最简单的四方向摇杆
  19. 我的物联网项目之 合伙人羊毛党
  20. 本地计算机无法启动theme服务,无法启动themes服务_Themes开机自动启动

热门文章

  1. Java简易学生管理(姓名查找,学号查找,添加成员)
  2. 用微信小程序开店之六——小程序组件2:“基础内容”
  3. Slicer学习笔记(四十二)slicer c++源码编译
  4. 论文笔记:nnU-Net: Self-adapting Frameworkfor U-Net-Based Medical Image Segmentation
  5. 苹果6s怎么会不支持电信版本?
  6. 谷歌的android官方刷机,谷歌 Android 7.0 ROM刷机包 for Nexus 6P 官方固件最新版
  7. UNBOUND 搭建 LDNS服务和使用bind搭建dnssec环境
  8. 全新安装Mac OSX 开发者环境 同时使用homebrew搭建 PHP,Nginx ,MySQL,Redis,Memcache ... ... (LNMP开发环境)
  9. 异步模式下的 Vhost Packed Ring 设计介绍
  10. 最新全志智能扫地机高性能芯片方案-MR133介绍