vector 是一种顺序容器,可以看作是可以改变大小的数组。

就像数组一样,vector 占用连续的内存地址来存储元素,因此可以像数组一样用偏移量来随机访问,但是它的大小可以动态改变,容器会自动处理内存分配问题。

在内部,vector 使用动态分配的数组来存储元素,当新元素插入时,如果现有的存储空间已经占满,则需要重新再分配一个新的数组,并且将之前的元素都移动到新的内存上。这个过程是非常耗时的,因此,vector 并不会在每次插入新元素时都重新分配内存。

相反,vector 容器可能会分配一些额外的内存来适应其大小的增长,因此,其真实容量可能比存储这些元素实际需要的内存要大。库通过不同的策略来平衡内存占用和空间再分配,但无论如何,空间分配只应在 vector 大小以对数增长的时候发生,以便在向量末尾插入单个元素可以做到均摊情况下是常数级的时间复杂度

因此,相对于数组,vector 会消耗更多的内存来换取更有效地对内存进行管理并且动态增长。

相对于其他动态容器,vector 支持随机访问,并且能相对高效地在末尾插入或者删除元素,但如果要在其他位置插入或者删除元素,vector 就会表现得很差,而且迭代器和引用也不是那么方便。

构造函数

  • explicit vector (const allocator_type& alloc = allocator_type()); 默认构造函数,构造出一个不包含任何元素的空的 vector;

  • explicit vector (size_type n); 构造出一个包含 \(n\) 个元素的 vector,默认会初始化为 0;

  • explicit vector (size_type n, const value_type& val, const allocator_type& alloc = allocator_type()); 构造出一个包含 \(n\) 个值为 \(val\) 的 vector;

  • vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()); 构造出一个包含迭代器 \([first, end)\) 范围内元素的 vector,注意左闭右开;

  • vector (const vector& x); 复制构造函数,构造出一个和 \(x\) 相同的 vector;

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main ()
  5. {
  6. vector<int> first; // 空的 vector
  7. vector<int> second (4, 100); // 包含 4 个值为 100 元素的 vector,[100, 100, 100, 100]
  8. vector<int> third (second.begin(), second.end()); // 包含 second 起始迭代器到终止迭代器区间元素的 vector,[100, 100, 100, 100]
  9. vector<int> fourth (third); // 对 third 的复制,[100, 100, 100, 100]
  10. // 数组也可以用来作为迭代器初始化 vector
  11. int myints[] = {16, 2, 77, 29};
  12. vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) ); //[16, 2, 77, 29]
  13. vector<int> sixth (4); // [0, 0, 0, 0]
  14. cout << "The contents of fifth are:";
  15. for (vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
  16. cout << ' ' << *it;
  17. cout << '\n';
  18. return 0;
  19. }

赋值运算

赋值运算会给容器赋予新的内容,替换掉旧的内容,同时改变其大小。

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main ()
  5. {
  6. vector<int> foo (3,0);
  7. vector<int> bar (5,0);
  8. bar = foo;
  9. foo = vector<int>();
  10. cout << "Size of foo: " << int(foo.size()) << '\n'; // 0
  11. cout << "Size of bar: " << int(bar.size()) << '\n'; // 3
  12. return 0;
  13. }

迭代器

  • iterator begin(); 返回指向 vector 中第一个元素的迭代器;
  • iterator end(); 返回一个迭代器,引用向量容器中的 past-the-end 元素,也即最后一个元素之后的理论元素;
  • reverse_iterator rbegin(); 返回指向 vector 中最后一个元素的反向迭代器,增加反向迭代器会使它们向前移动;
  • reverse_iterator rend(); 返回一个反向迭代器,指向向量中第一个元素之前的理论元素;
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main ()
  5. {
  6. vector<int> myvector;
  7. for(int i = 0; i < 5; i++)
  8. {
  9. myvector.push_back(i);
  10. }
  11. vector<int>::iterator it = myvector.begin();
  12. for (; it != myvector.end(); it++)
  13. {
  14. cout << *it << '\t';
  15. }
  16. cout << endl;
  17. vector<int>::reverse_iterator rit = myvector.rbegin();
  18. for (; rit != myvector.rend(); rit++)
  19. {
  20. cout << *rit << '\t';
  21. }
  22. cout << endl;
  23. return 0;
  24. }
  25. // 0 1 2 3 4
  26. // 4 3 2 1 0

也可以对向量建立指针,然后通过指针来访问成员函数。或者建立引用。

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main ()
  5. {
  6. vector<int> myvector;
  7. for(int i = 0; i < 5; i++)
  8. {
  9. myvector.push_back(i);
  10. }
  11. vector<int> *p = &myvector;
  12. p->push_back(5);
  13. vector<int>::reverse_iterator rit = p->rbegin();
  14. // vector<int>::reverse_iterator rit = (*p).rbegin();
  15. for (; rit != p->rend(); rit++)
  16. {
  17. cout << *rit << '\t';
  18. }
  19. cout << endl;
  20. vector<int> &ref_myvector = myvector;
  21. ref_myvector.push_back(6);
  22. vector<int>::iterator it = ref_myvector.begin();
  23. for (; it != ref_myvector.end(); it++)
  24. {
  25. cout << *it << '\t';
  26. }
  27. cout << endl;
  28. return 0;
  29. }
  30. // 5 4 3 2 1 0
  31. // 0 1 2 3 4 5 6

容量

  • size_type size() const; 返回向量中元素的个数;
  • size_type max_size() const; 返回向量中最大可能包含的元素个数,但这只是理论上的;
  • void resize (size_type n, value_type val = value_type()); 重新设置向量的大小使之包含 \(n\) 个元素;如果 \(n\) 小于现有向量大小,则只保留前 \(n\) 个元素;如果 \(n\) 大于现有向量大小,那么在末尾插入元素来使向量大小达到 \(n\) ;如果 \(n\) 大于现有向量容量,那么会自动重新分配内存;
  • size_type capacity() const; 返回向量当前分配的内存可以包含多少个元素;
  • bool empty() const; 返回当前向量是否为空,也就是大小是否为零;
  • void reserve (size_type n); 让向量当前分配的内存至少可以包含 \(n\) 个元素;
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main ()
  5. {
  6. vector<int> myvector;
  7. cout << "max_size: " << myvector.max_size() << endl;
  8. // 添加元素的过程中容量会不断增大
  9. for(int i = 0; i < 10; i++)
  10. {
  11. myvector.push_back(i);
  12. cout << "size: " << myvector.size() << '\t';
  13. cout << "capacity: " << myvector.capacity() << endl;
  14. }
  15. vector<int> othervector;
  16. othervector.reserve(100);
  17. // 添加元素的过程中大小不超过 100 就不会增大
  18. for(int i = 0; i < 10; i++)
  19. {
  20. othervector.push_back(i);
  21. cout << "size: " << othervector.size() << '\t';
  22. cout << "capacity: " << othervector.capacity() << endl;
  23. }
  24. return 0;
  25. }

元素访问

  • reference operator[] (size_type n); 像数组一样访问位置 \(n\) 处的元素,但不会进行边界检测;
  • reference at (size_type n); 访问位置 \(n\) 处的元素,但会进行边界检测;
  • reference front(); 返回向量中第一个元素的引用;
  • reference back(); 返回向量中最后一个元素的引用;
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main ()
  5. {
  6. vector<int> myvector;
  7. for(int i = 0; i < 10; i++)
  8. {
  9. myvector.push_back(i);
  10. }
  11. cout << myvector.front() << endl;
  12. cout << myvector.back() << endl;
  13. // 此处越界访问向量,不会提示
  14. for(int i = 0; i <= myvector.size(); i++)
  15. {
  16. cout << myvector[i] << '\t';
  17. }
  18. cout << endl;
  19. // 此处越界访问向量,会抛出一个 out_of_range 异常
  20. for(int i = 0; i <= myvector.size(); i++)
  21. {
  22. cout << myvector.at(i) << '\t';
  23. }
  24. cout << endl;
  25. return 0;
  26. }

向量修改

  • void assign (InputIterator first, InputIterator last); 给向量重新分配迭代器 \([first, end)\) 范围内的元素,注意左闭右开;
  • void assign (size_type n, const value_type& val); 给向量重新分配 \(n\) 个值 \(val\) 的元素;
  • void push_back (const value_type& val); 在向量末尾添加一个元素;
  • void pop_back(); 从向量末尾删除一个元素;
  • iterator insert (iterator position, const value_type& val); 在迭代器位置前面插入一个元素,返回指向第一个新插入元素的迭代器
  • void insert (iterator position, size_type n, const value_type& val); 在迭代器位置前面插入 \(n\) 个值 \(val\) 的元素;
  • void insert (iterator position, InputIterator first, InputIterator last); 在迭代器位置前面插入迭代器 \([first, end)\) 范围内的元素;
  • iterator erase (iterator position); 删除迭代器位置的元素,返回最后一个被删除元素的后面一个元素的迭代器
  • iterator erase (iterator first, iterator last); 删除迭代器 \([first, end)\) 范围内的元素,返回最后一个被删除元素的后面一个元素的迭代器
  • void swap (vector& x); 和向量 \(x\) 进行交换,两个向量元素类型相同,但大小可能不同;
  • void clear(); 清空向量;
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main ()
  5. {
  6. vector<int> first;
  7. vector<int> second;
  8. vector<int> third;
  9. first.assign(7, 100); // [100, 100, 100, 100, 100, 100, 100]
  10. vector<int>::iterator it;
  11. it = first.begin() + 1;
  12. second.assign(it, first.end() - 1); // [100, 100, 100, 100, 100]
  13. int myints[] = {1776, 7, 4};
  14. third.assign(myints, myints + 3); // [1776, 7, 4]
  15. cout << "Size of first: " << int (first.size()) << '\n';
  16. cout << "Size of second: " << int (second.size()) << '\n';
  17. cout << "Size of third: " << int (third.size()) << '\n';
  18. vector<int> myvector (3, 100); // [100, 100, 100]
  19. it = myvector.begin() + 1;
  20. it = myvector.insert(it, 200); // [100, 200, 100, 100],此时 it 指向新插入的元素 200
  21. myvector.insert(it, 2, 300); // [100, 300, 300, 200, 100, 100],此时 it 无效了
  22. it = myvector.begin();
  23. vector<int> anothervector (2, 400); // [400, 400]
  24. myvector.insert(it + 2, anothervector.begin(), anothervector.end());
  25. // [100, 300, 400, 400, 300, 200, 100, 100]
  26. int myarray [] = {501, 502, 503};
  27. myvector.insert (myvector.begin(), myarray, myarray + 3);
  28. // [501, 502, 503, 100, 300, 400, 400, 300, 200, 100, 100]
  29. cout << "myvector contains:";
  30. for (it = myvector.begin(); it < myvector.end(); it++)
  31. cout << ' ' << *it;
  32. cout << '\n';
  33. myvector.clear();
  34. for (int i = 1; i <= 10; i++) myvector.push_back(i);
  35. // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  36. it = myvector.erase(myvector.begin() + 5);
  37. // [1, 2, 3, 4, 5, 7, 8, 9, 10],此时 it 指向 6 后面的元素 7
  38. it = myvector.erase(myvector.begin(), myvector.begin() + 3);
  39. // [4, 5, 7, 8, 9, 10],此时 it 指向 3 后面的元素 4
  40. cout << "myvector contains:";
  41. for (unsigned i = 0; i < myvector.size(); ++i)
  42. cout << ' ' << myvector[i];
  43. cout << '\n';
  44. return 0;
  45. }

参考资料 [http://www.cplusplus.com]

获取更多精彩,请关注「seniusen」!

C++ 学习笔记之——STL 库 vector的更多相关文章

  1. C++ 学习笔记之——STL 库 queue

    1. 队列 queue 队列是一种容器适配器,专门用来满足先进先出的操作,也就是元素在容器的一端插入并从另一端提取. bool empty() const; 返回队列是否为空: size_type s ...

  2. 学习笔记:STL

    第一部分:(参考百度百科) 一.STL简介 STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.它是由Alexander Stepanov.Me ...

  3. iOS学习笔记16-数据库SQLite

    一.数据库 在项目开发中,通常都需要对数据进行离线缓存的处理,如新闻数据的离线缓存等.离线缓存一般都是把数据保存到项目的沙盒中.有以下几种方式: 归档:NSKeyedArchiver 偏好设置:NSU ...

  4. C++ Primer学习笔记2--c++标准库中的 vector、string 和 bitset 类型

    一.string    #include <string>  using std::string    初始化函数:    string s1;        默认构造函数 s1 为空串 ...

  5. STL学习:STL库vector、string、set、map用法

    本文仅介绍了如何使用它们常用的方法. vector 1.可随机访问,可在尾部插入元素:2.内存自动管理:3.头文件#include <vector> 1.创建vector对象 一维: (1 ...

  6. Effective STL 学习笔记 Item 16:vector, string & C API

    有时需要支持 C 的接口,但这并不复杂. 对于 vector 来讲, \(v[0]\) 的地址 \(\&v[0]\) 即可作为数组指针传递给 C API: 1: // Legacy C API ...

  7. C++ 学习笔记之 STL 队列

    一.  引言 在算法以及数据结构的实现中,很多地方我们都需要队列(遵循FIFO,先进先出原则). 为了使用队列,我们可以自己用数组来实现队列,但自己写太麻烦不说,并且还很容易出错. 好在C++的STL ...

  8. 重温JSP学习笔记--JSTL标签库

    以前写jsp的时候对jstl标签库是有些抵触的,因为我觉得嵌入java代码的方式几乎无往不利,没有必要使用标签库,不过这次复习还是好好地学习了一下,发现这个还是很有用处的,用得好能省不少事,JSTL是 ...

  9. OpenGL学习笔记0——安装库

    最近需要做一个基于Zigbee室内无线定位的系统,受到TI公司ZigBee Sensor Monitor软件的启发,打算用OpenGL来做一个3D显示空间内物体位置的程序.学习阶段选择VS2010+O ...

随机推荐

  1. 身份认证系统(三)什么是OAuth2

    本文准备用最简单的语言告诉大家什么是OAuth2 ,OAuth2是干什么的. 我们有一个资源服务器,资源服务器中有一系列的用户数据. 现在有一个应用想想要获取我们的用户数据. 那么最简单的方法就是我们 ...

  2. trunc(sysdate)的含义是什么

    1.ORACLE中TRUNC是截取的函数

  3. ABAP术语-Transaction

    Transaction 原文:http://www.cnblogs.com/qiangsheng/archive/2008/03/19/1112804.html Logical process in ...

  4. Django学习笔记5-url

    先来看一下普通的url的格式 {% url 'login_action'%} 但由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回 ...

  5. php ecshop 二级域名切换跳转时session不同步,解决session无法共享同步导致无法登陆或者无法退出的问题

    echshop基础上做了单点登录的 一级域名与二级域名 退出时 清空session 都是一级域名的session 因为二级域名的session是设置在二级域名上的 echshop基础上没有做单点登录的 ...

  6. 使用Scala开发Apache Kafka的TOP 20大好用实践

    本文作者是一位软件工程师,他对20位开发人员和数据科学家使用Apache Kafka的方式进行了最大限度得深入研究,最终将生产实践环节需要注意的问题总结为本文所列的20条建议. Apache Kafk ...

  7. Python基本语法元素

      静态语言(C/C++.Java):脚本语言(python.JavaScript.PHP) IPO(Input.Process.Output) #:python中的注释符号:'''    ''':多 ...

  8. django创建第一个视图-4

    创建视图 打开 demo 应用下的 views.py 文件,添加代码 from django.http import HttpResponse from django.shortcuts import ...

  9. ruby中的return方法及class实例方法的initialize方法

    return是函数的返回值 class Mtring def initialize(str) @name = str end def aa ary = @name.split(/:/) return ...

  10. 计算阶乘的和v2.0(4分)

    题目内容: 假设有这样一个三位数m,其百位.十位和个位数字分别是a.b.c,如果m= a!+b!+c!,则这个三位数就称为三位阶乘和数(约定0!=1).请编程计算并输出所有的三位阶乘和数. 函数原型: ...