【C++】STL—容器—vector介绍

分手后的思念是犯贱 2022-11-22 00:12 395阅读 0赞

文章目录

  • 一、vector的介绍
    • 1、概念
    • 2、分配空间策略
    • 3、特点
  • 二、vector的使用
    • 1、vector的定义
    • 2、vector iterator 的使用
    • 3、vector 空间增长
    • 4、vector 增删查改
    • 5、vector 迭代器失效问题
  • 三、vector的模拟实现

一、vector的介绍

1、概念

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

2、分配空间策略

vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。

3、特点

与其它动态序列容器相比(deques, lists and forward_lists),vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和 forward_lists统一的迭代器和引用更好。

二、vector的使用

1、vector的定义

  1. void TestVector1()
  2. {
  3. vector<int> v1;//无参构造
  4. vector<int> v2(10,5);//构造10个整形5
  5. int array[] = {
  6. 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  7. vector<int> v3(array, array + sizeof(array) / sizeof(array[0]));//构造整个array数组
  8. vector<int> v5(v3);//拷贝构造
  9. vector<int> v6{
  10. 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };//构造整形数组
  11. }

2、vector iterator 的使用

  1. vector<int> v3(array, array + sizeof(array) / sizeof(array[0]));
  2. vector<int>::iterator it = v3.begin();//获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置iterator/const_iterator
  3. while (it != v3.end())
  4. {
  5. cout << *it << " ";
  6. ++it;
  7. }
  8. cout << endl;
  9. vector<int> v5(v3);
  10. auto rit = v5.rbegin();//获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的 reverse_iterator
  11. while (rit != v5.rend())
  12. {
  13. cout << *rit << " ";
  14. ++rit;
  15. }
  16. cout << endl;

在这里插入图片描述

3、vector 空间增长

  1. void TestVector2()
  2. {
  3. vector<int> v{
  4. 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  5. cout << v.size() << endl;//获取数据个数
  6. cout << v.capacity() << endl;//获取容量大小
  7. if (v.empty())//判断是否为空
  8. {
  9. cout << "v empty" << endl;
  10. }
  11. else
  12. {
  13. cout << "v not empty" << endl;
  14. }
  15. }
  16. v.reserve(40);//将容量扩大到40
  17. v.resize(20, 100);//将数据个数设置为20,不够用100补充

capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。

4、vector 增删查改

  1. void TestVector6()
  2. {
  3. // 注意:push_back和insert在插入元素期间,可能需要扩容
  4. vector<int> v;
  5. v.push_back(1);//尾插
  6. v.push_back(2);
  7. v.push_back(3);
  8. v.push_back(4);
  9. v.pop_back();//尾删
  10. v.insert(v.begin(), 0);//头部位置插入0
  11. // 在元素2的位置插入10个值为5的元素
  12. v.insert(find(v.begin(), v.end(), 2), 10, 5);
  13. //将数组array中的元素插入到v的尾部
  14. int array[] = {
  15. 4, 5, 6, 7 };
  16. v.insert(v.end(), array, array + sizeof(array) / sizeof(array[0]));
  17. }
  18. vector<int> v1{
  19. 1, 2, 3 };
  20. vector<int> v2{
  21. 4, 5, 6, 7, 8, 9 };
  22. v1.swap(v2);//v1和v2交换
  23. vector<int> v3{
  24. 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  25. v3.erase(v3.begin());//头部元素删除
  26. v3.erase(v3.begin(), v3.begin() + 3);//头部元素开始,后3个元素删除

5、vector 迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T*。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

对于vector可能会导致其迭代器失效的操作有:

  1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、 push_back等
  2. 指定位置元素的删除操作–erase

    void TestVector11()
    {

    1. vector<int> v{
    2. 1, 2, 3 };
    3. auto it = v.begin();
    4. v.clear();
    5. cout << *it << endl;//迭代器失效
    6. while (it != v.end())
    7. {
    8. it = v.erase(it);
    9. it++;//迭代器失效
    10. }

    }

erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代 器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。

迭代器失效解决办法:在使用前,对迭代器重新赋值即可。

三、vector的模拟实现

  1. #include <assert.h>
  2. namespace bite
  3. {
  4. template<class T>
  5. class vector
  6. {
  7. public:
  8. typedef T* iterator;
  9. public:
  10. vector()
  11. : start(nullptr)
  12. , finish(nullptr)
  13. , endofstorage(nullptr)
  14. {
  15. }
  16. vector(int n, const T& data = T())
  17. : start(new T[n])
  18. , finish(start + n)
  19. , endofstorage(finish)
  20. {
  21. for (int i = 0; i < n; ++i)
  22. {
  23. start[i] = data;
  24. }
  25. }
  26. template<class Iterator>
  27. vector(Iterator first, Iterator last)
  28. {
  29. // 确定该区间中有多少个元素
  30. Iterator it = first;
  31. size_t count = 0;
  32. while (it != last)
  33. {
  34. count++;
  35. ++it;
  36. }
  37. // 给当前对象开辟空间,并初始化成员变量
  38. start = new T[count];
  39. finish = start;
  40. endofstorage = start + count;
  41. //赋值
  42. while (first != last)
  43. {
  44. *finish++ = *first++;
  45. }
  46. }
  47. vector(const vector<T>& v)
  48. {
  49. size_t vsize = v.size();
  50. start = new T[vsize];
  51. finish = endofstorage = start + vsize;
  52. for (size_t i = 0; i < vsize; ++i)
  53. start[i] = v[i];
  54. }
  55. ~vector()
  56. {
  57. if (start)
  58. {
  59. delete[] start;
  60. start = finish = endofstorage = nullptr;
  61. }
  62. }
  63. iterator begin()
  64. {
  65. return start;
  66. }
  67. iterator end()
  68. {
  69. return finish;
  70. }
  71. size_t size()const
  72. {
  73. return finish - start;
  74. }
  75. size_t capacity()const
  76. {
  77. return endofstorage - start;
  78. }
  79. bool empty()const
  80. {
  81. return start == finish;
  82. }
  83. void resize(size_t newsize, const T& data = T())
  84. {
  85. size_t oldsize = size();
  86. if (newsize <= oldsize)
  87. {
  88. finish = start + newsize;
  89. }
  90. else
  91. {
  92. if (newsize > capacity())
  93. reserve(newsize);
  94. for (size_t i = oldsize; i < newsize; ++i)
  95. start[i] = data;
  96. finish = start + newsize;
  97. }
  98. }
  99. void reserve(size_t newcapacity)
  100. {
  101. size_t oldcapacity = capacity();
  102. size_t oldsize = size();
  103. if (newcapacity > oldcapacity)
  104. {
  105. // 开辟新空间
  106. T* temp = new T[newcapacity];
  107. // 拷贝元素
  108. for (size_t i = 0; i < oldsize; ++i)
  109. temp[i] = start[i];
  110. // 释放旧空间
  111. delete start;
  112. start = temp;
  113. finish = start + oldsize;
  114. endofstorage = start + newcapacity;
  115. }
  116. }
  117. //acess
  118. T& operator[](size_t index)
  119. {
  120. assert(index < size());
  121. return start[index];
  122. }
  123. const T&operator[](size_t index)const
  124. {
  125. assert(index < size());
  126. return start[index];
  127. }
  128. T& front()
  129. {
  130. return start[0];
  131. }
  132. const T& front()const
  133. {
  134. return start[0];
  135. }
  136. T& back()
  137. {
  138. return start[size() - 1];
  139. }
  140. const T& back()const
  141. {
  142. return start[size() - 1];
  143. }
  144. void push_back(const T& data)
  145. {
  146. if (size() == capacity())
  147. reserve(capacity() * 2 + 3);
  148. *finish++ = data;
  149. }
  150. void pop_back()
  151. {
  152. if (empty())
  153. return;
  154. --finish;
  155. }
  156. iterator insert(iterator pos, const T& data)
  157. {
  158. assert(pos <= end());
  159. if (size() == capacity())
  160. reserve(capacity() * 2);
  161. auto it = end();
  162. while (it > pos)
  163. {
  164. *it = *(it - 1);
  165. --it;
  166. }
  167. *pos = data;
  168. ++finish;
  169. return pos;
  170. }
  171. iterator erase(iterator pos)
  172. {
  173. assert(pos < end());
  174. if (size() == 1)
  175. {
  176. pop_back();
  177. return end();
  178. }
  179. auto it = pos;
  180. while (it < end())
  181. {
  182. *it = *(it + 1);
  183. ++it;
  184. }
  185. --finish;
  186. return pos;
  187. }
  188. void clear()
  189. {
  190. finish = start;
  191. }
  192. void swap(const vector<T>& v)
  193. {
  194. std::swap(start, v.start);
  195. std::swap(finish, v.finish);
  196. std::swap(endofstorage, v.endofstorage);
  197. }
  198. private:
  199. iterator start;
  200. iterator finish;
  201. iterator endofstorage;
  202. };
  203. }
  204. #include <iostream>
  205. using namespace std;
  206. #include <string>
  207. void TestMyvector1()
  208. {
  209. bite::vector<int> v1;
  210. bite::vector<int> v2(10, 5);
  211. for (size_t i = 0; i < v2.size(); ++i)
  212. cout << v2[i] << " ";
  213. cout << endl;
  214. int array[] = {
  215. 1, 2, 3, 4, 5 };
  216. bite::vector<int> v3(array, array + 5);
  217. auto it = v3.begin();
  218. while (it!=v3.end())
  219. {
  220. cout << *it << " ";
  221. ++it;
  222. }
  223. cout << endl;
  224. std::string s("hello");
  225. bite::vector<char> vc(s.begin(), s.end());
  226. bite::vector<int> v4(v3);
  227. for (auto e : v4)
  228. cout << e << " ";
  229. cout << endl;
  230. }
  231. void TestMyvector2()
  232. {
  233. bite::vector<int> v;
  234. v.push_back(1);
  235. v.push_back(2);
  236. v.push_back(3);
  237. v.push_back(4);
  238. for (auto e : v)
  239. cout << e << " ";
  240. cout << endl;
  241. v.pop_back();
  242. v.pop_back();
  243. for (auto e : v)
  244. cout << e << " ";
  245. cout << endl;
  246. v.insert(v.begin(), 0);
  247. for (auto e : v)
  248. cout << e << " ";
  249. cout << endl;
  250. v.erase(v.begin());
  251. for (auto e : v)
  252. cout << e << " ";
  253. cout << endl;
  254. v.clear();
  255. cout << v.size() << endl;
  256. cout << v.capacity() << endl;
  257. }
  258. void TestMyvector3()
  259. {
  260. bite::vector<int> v;
  261. v.push_back(1);
  262. v.push_back(2);
  263. v.push_back(3);
  264. v.push_back(4);
  265. cout << v[0] << endl;
  266. cout << v.front() << endl;
  267. cout << v.back() <<endl;
  268. v.resize(8, 5);
  269. cout << v.size() << endl;
  270. cout << v.capacity() << endl;
  271. for (auto e : v)
  272. {
  273. cout << e << " ";
  274. }
  275. cout << endl;
  276. v.resize(15, 6);
  277. cout << v.size() << endl;
  278. cout << v.capacity() << endl;
  279. for (auto e : v)
  280. {
  281. cout << e << " ";
  282. }
  283. cout << endl;
  284. v.resize(20, 6);
  285. cout << v.size() << endl;
  286. cout << v.capacity() << endl;
  287. for (auto e : v)
  288. {
  289. cout << e << " ";
  290. }
  291. cout << endl;
  292. v.resize(12);
  293. cout << v.size() << endl;
  294. cout << v.capacity() << endl;
  295. for (auto e : v)
  296. {
  297. cout << e << " ";
  298. }
  299. cout << endl;
  300. v.resize(5);
  301. cout << v.size() << endl;
  302. cout << v.capacity() << endl;
  303. for (auto e : v)
  304. {
  305. cout << e << " ";
  306. }
  307. cout << endl;
  308. }

发表评论

表情:
评论列表 (有 0 条评论,395人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Vector容器

    Vector 容器 一、 简介 vector 是将元素置于一个动态数组中加以管理的容器 vector可以随机存取元素(支持索引值直接存取,用\[\]操作符或at()函数)

    相关 Vector容器

    一、vector容器。 1、vector容器基本概念。 1)功能: vector容器数据结构与数组非常相似,也称为单端数组。 2)vector与普通数组区别?

    相关 c++容器vector介绍

    vector简介     vector是STL中最常见的容器,它是一种顺序容器,支持随机访问。vector是一块连续分配的内存,从数据安排的角度来讲,和数组极其相似,不同的地

    相关 Vector介绍

    C++ Vector (向量容器) 是一个线性顺序结构。相当于数组,但其大小可以不预先指定,并且自动扩展。它可以像数组一样被操作,由于它的特性我们完全可以将vector 看作