C++初阶 Vector的介绍和使用

简介: C++初阶 Vector的介绍和使用

Vector的介绍


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

这个是什么意思呢? 还记不记得我们之前学的顺序表? 这个是不是和顺序表很相似啊


如果说还有同学不清楚的话可以试着看这篇文章


初阶数据结构 顺序表的讲解


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


这里我们主要需要注意的就是一点 我们可以使用下标来访问vector


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

小。

所以说我们一般会按照两倍进行扩容来避免频繁扩容


4.vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存

储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是

对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。


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

长。


6.与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末

尾添加和删除元素相对高效。对于其他不在末尾的删除和插入操作,效率更低。比起list和forward_list

统一的迭代器和引用更好。


这个时候我们来总结下 需要知道的是什么呢?


它底层实际上和顺序表差不多 可以使用下标来访问 为了提高效率扩容一般是按照两倍扩容


Vector的使用


定义


定义方式有以下几种


方法一: 构造一个某类型的空容器


vector<int> v1; // 构造一个int类型的空容器


方法二:构造一个含有n个val值的容器


vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2

方式三:拷贝构造


vector<int> v3(v2);


方式四:使用迭代器拷贝


vector<int> v4(v2.begin(), v2.end()); //迭代器拷贝构造


注:使用别的容器的迭代器也可以拷贝(不是vector 以string为例)


string s1("hello world");
  vector<char> v5(s1.begin(), s1.end()); // 使用string类的迭代器构造


空间相关


szie

这个函数很简单 返回容器中占用的元素个数


代码和效果图如下


vector<int> v1; // 构造一个int类型的空容器
  vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
  cout << v2.size() << endl; // 输出v2容器中有效元素个数


ebd10fff7d584f0893e3171ed7032d24.png


capacity

返回当前容器的最大容量 用法和size类似


代码和效果图如下


vector<int> v1; // 构造一个int类型的空容器
  vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
  cout << v2.capacity() << endl; // 输出v2容器中最大能容纳的元素个数

e992edb3e0f047eab88c621ff76aac77.png


reszie

resize函数可以改变容器的有效元素个数


使用规则是这样子的


1 假设所给值小于当前容器size值 size缩小至所给值

2 假设所给值大于当前容器size值并且小于capacity值 size扩大至所给值 扩大的范围赋值0

3 假设所给值大于当前容器size值并且大于capacity值 先扩容 后面操作和2一样

代码和效果图如下


vector<int> v1; // 构造一个int类型的空容器
  vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
  cout << v2.size() << endl; // 输出v2容器中有效元素个数 
  v2.resize(100);  // 扩大size到100
  cout << v2.size() << endl; // 输出v2容器中有效元素个数


reserve

reserve函数可以改变容器的最大容量


使用规则如下


1 假设所给值小于当前容量值 什么都不做

2 假设所给值大于当前容量值 扩容至所给值


代码和效果图如下


vector<int> v1; // 构造一个int类型的空容器
  vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
  cout << v2.capacity() << endl; // 输出v2容器中最大能容纳的元素个数 
  v2.reserve(100); // 扩大capacity到100
  cout << v2.capacity() << endl; // 输出v2容器中最大能容纳的元素个数

de33266e69c6430ba04b689d7f78c45e.png


empty

empty函数可以判断容器是否为空


代码和使用效果图如下


void test4()
{
  vector<int> v1; // 构造一个int类型的空容器
  cout << v1.empty() << endl;
  vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
  cout << v2.empty() << endl;
}

33a55eb3d73a46cd93205d1e0e45cc9c.png


迭代器相关


dd77a5cab0c64fee89fd5a64ae25091c.png

begin和end


通过begin函数我们可以得到容器中第一个元素的正向迭代器

通过end函数我们可以得到容器中最后一个元素的正向迭代器


下面我们使用这个迭代器来遍历数组


代码和效果图如下

vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
  vector<int>::iterator it = v2.begin();
  while (it!=v2.end())
  {
  cout << *it << " ";
  it++;
  }

297d5e9d95ca4ca29de54a5db8262fd3.png


rbegin和rend


通过rbegin函数我们可以得到容器中第一个元素的反向迭代器

通过rend函数我们可以得到容器中最后一个元素的正向迭代器


下面我们使用这个迭代器来遍历数组


代码和效果图如下


注意 我们这里正向迭代器和反向迭代器的定义并不相同


vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
  vector<int>::reverse_iterator it = v2.rbegin();
  while (it != v2.rend())
  {
  cout << *it << " ";
  it++;
  }


6d1c580376b4455f9852f43171d94c90.png


增删查改


push_back

我们使用这个函数来向容器中插入一个值


代码和使用效果如下


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  vector<int>::iterator it = v1.begin();
  while (it != v1.end())
  {
  cout << *it << " ";
  it++;
  }


67deaf9b09df44d585dba4a2c3cecfc3.png


pop_back


我们使用这个函数来向容器中删除一个值


代码和使用效果如下


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.pop_back();
  v1.pop_back();
  v1.pop_back();
  vector<int>::iterator it = v1.begin();
  while (it != v1.end())
  {
  cout << *it << " ";
  it++;
  }

5df55902ea914aba89b0ef2da621679c.png


insert


inset 函数有两个用法


一 选择一个位置(迭代器) 选择一个我们要插入的元素


代码和显示效果如下


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.insert(v1.begin(), 100); // 我们再开头插入一个元素100
  vector<int>::iterator it = v1.begin();
  while (it != v1.end())
  {
  cout << *it << " ";
  it++;
  }


4305139244434b4a95178acd97a8600d.png

二 选择一个位置(迭代器) 选择一个我们要插入的元素的数量 选择一个我们要插入的元素


代码和显示效果图如下


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.insert(v1.begin(), 100 , 5); // 我们头插100个5
  // 我们之后再试试5个100
  vector<int>::iterator it = v1.begin();
  while (it != v1.end())
  {
  cout << *it << " ";
  it++;
  }

c8434141ee434a4898738a6dc0436f0c.png

ebbf1a2dfbe6471b91559526238e573f.png


earse


和insert对应 earse也有两种使用方式


一. 删除指定位置的内容(迭代器)


代码和显示效果如下


void test8()
{
  vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.erase(v1.begin());
  vector<int>::iterator it = v1.begin();
  while (it != v1.end())
  {
  cout << *it << " ";
  it++;
  }
}

73ab398976a94c6195e2249df444aca8.png



一. 删除指定位置的内容(迭代器) 删除区间的末尾(左闭右开)


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.erase(v1.begin(), v1.begin()+2);
  // 左边是闭区间 右边是开区间(不删除)
  vector<int>::iterator it = v1.begin();
  while (it != v1.end())
  {
  cout << *it << " ";
  it++;
  }

421627355ee5456fb80a42a395f84845.png


find


find函数可以找到容器中我们要寻找的值 并且返回迭代器


find函数有三个参数 迭代器左区间 迭代器右区间 要查找元素 (左闭右开)


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  // v1.erase(v1.begin(), v1.begin()+2);
  vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);  // 找到3
  v1.erase(pos); // 删除3
  vector<int>::iterator it = v1.begin();
  while (it != v1.end())
  {
  cout << *it << " ";
  it++;
  }

efc8c07014464feb9ea6ccf26bfe7b83.png



注意!!!!!!


这里的find函数的头文件是 algorithm !!!


一定要记住! 不是容器的默认函数


swap


通过swap我们可以交换两个容器的值


元素遍历


我们这里遍历有三种方式


迭代器遍历范围for或者方括号遍历


我们这里展示下范围for(其实就是迭代器)


还有方括号遍历


代码和效果图如下


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.push_back(5);
  v1.push_back(6);
  vector<int>::iterator it = v1.begin();
  for (auto& x : v1)
  {
  cout << x << " ";
  }
  cout << endl;
  for (size_t i = 0; i < v1.size(); i++)
  {
  cout << v1[i] << " ";
  }

06eb38d253b944c5bc922651a843cc3f.png


迭代器失效相关问题


实例一


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.push_back(5);
  v1.push_back(6);
  vector<int>::iterator it = find(v1.begin(), v1.end(), 2); // 意思是我们要删除2
  v1.erase(v1.begin()); //删除头元素
  v1.erase(it); //删除元素2

093e467e410d424ba4db9a9e4f9fc5fd.png



实例二


void test10()
{
  vector<int> v;
  for (size_t i = 1; i <= 6; i++)
  {
  v.push_back(i);
  }
  vector<int>::iterator it = v.begin();
  while (it != v.end())
  {
  if (*it % 2 == 0) //删除容器当中的全部偶数
  {
    v.erase(it);
  }
  it++;
  }
}

96e1caefc09a4b74a69c28b42c37198b.png



这两个错误都是由于迭代器失效引发的


不难发现 我们在使用迭代器之前都对整个容器进行了增删改操作


这种情况就是导致迭代器失效的直接原因


解决方法也很简单 使用迭代器之前重新赋值一下就好了


解决代码和效果如下


实例一


对于实例一来说我们只需要再找一次我们要删除位置的迭代器就好了


vector<int> v1; // 创造一个空容器
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.push_back(5);
  v1.push_back(6);
  vector<int>::iterator it = find(v1.begin(), v1.end(), 2); // 意思是我们要删除2
  v1.erase(v1.begin()); //删除头元素
  it = find(v1.begin(), v1.end(), 2); // 意思是我们要删除2
  v1.erase(it); //删除元素2
  vector<int>::iterator it1 = v1.begin();
  while (it1 != v1.end())
  {
  cout << *it1 << " ";
  it1++;
  }


1fb523a934784fe095b91abb942eaace.png


实例二


对于实例二也是一样的


我们只需要在增删改之后重新赋值迭代器就好了


vector<int> v;
  for (size_t i = 1; i <= 6; i++)
  {
  v.push_back(i);
  }
  vector<int>::iterator it = v.begin();
  while (it != v.end())
  {
  if (*it % 2 == 0) //删除容器当中的全部偶数
  {
    it = v.erase(it);
  }
  else
  {
    it++;
  }
  }
  vector<int>::iterator it1 = v.begin();
  while (it1 != v.end())
  {
  cout << *it1 << " ";
  it1++;
  }


735a968766b24d0ba2ab437b9e595173.png


总结


本文主要讲解了vector的介绍和使用


由于作者水平有限 错误在所难免 希望大佬看到之后可以及时指正


如果这篇文章帮助到了你 别忘记一键三连啊


阿尼亚 哇酷哇酷!


相关文章
|
3月前
|
存储 编译器 C++
【C++】vector介绍+模拟实现
【C++】vector介绍+模拟实现
|
21天前
|
存储 C++ 索引
【C++打怪之路Lv9】-- vector
【C++打怪之路Lv9】-- vector
16 1
|
1月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化2
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
57 6
|
1月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化1
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
51 7
|
1月前
|
编译器 C++
【C++】—— vector模拟实现
【C++】—— vector模拟实现
|
1月前
|
编译器 C语言 C++
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
44 3
|
1月前
|
C++
【C++】C++ STL探索:Vector使用与背后底层逻辑(三)
【C++】C++ STL探索:Vector使用与背后底层逻辑
|
1月前
|
编译器 Linux C++
【C++】C++ STL探索:Vector使用与背后底层逻辑(二)
【C++】C++ STL探索:Vector使用与背后底层逻辑
|
1月前
|
编译器 C++ 容器
【C++】C++ STL探索:Vector使用与背后底层逻辑(一)
【C++】C++ STL探索:Vector使用与背后底层逻辑
|
26天前
|
算法 C++ 容器
C++之打造my vector篇(下)
C++之打造my vector篇(下)
26 0