• 【C++】vector的介绍 | 常见接口的使用


    目录

    vector的介绍

    常见接口

    构造函数

    尾插push_back()

    vector的遍历

    1.用方括号+下标 遍历:

    2.调用at()来访问:

    3.用迭代器遍历:

    4.范围for遍历:

    vector的空间修改

    vector增删查改

    覆盖assign()

    查找find()

    插入insert()

    删除erase()

    排序sort()

    string与vector的区别


    本篇先对vector做一个介绍,然后把常用的接口演示一下。

    由于vector的许多接口和string那儿的高度重合,所以这里就不详讲了,主要做一个了解。只要掌握几个最重要的接口,其余的用到时 查文档就好。

    vector的介绍

    vector是一个类模板。它能够容纳各种类型的对象作为其元素,并且可以动态地调整大小。可以理解为动态数组

    它像数组,又不像。

    像数组的是:vector也采用的连续存储空间来存储元素。这意味着可以采用下标对vector的元素进行访问,和数组一样高效。

    不像数组的是:它的大小是可以动态改变的,而且它的大小会被容器自动处理。

    本质来说,vector使用动态分配数组来存储它的元素。

    当新元素插入时候,这个数组需要被重新分配大小,为了增加存储空间。

    其做法是,分配一个新的数组,然后将全部元素移到这个数组。

    就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。

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

    不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。

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

    与其它动态序列容器相比(deque、list 、forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。

    对于其他不在末尾的删除和插入操作,效率更低。

    常见接口

    包头文件:

    #include

    构造函数

    两个标了🚩的要记住:

    构造函数声明接口说明
    vector();(重点)🚩无参构造
    vector(size_type n, const value_type& val = value_type());构造并初始化n个val
    vector (const vector& x); 🚩拷贝构造
    vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造

    我们在使用时,要注意vector是一个类模板,要实例化成 具体的类型 来使用:

    1. vector<int> v1;       //创建一个int类型的,空的v1
    2. vector<int> v2(5, 1); //v2含5个1
    3. vector<int> v3(v2);   //拷贝构造
    4. vector<int> v4(v3.begin(), v3.end());   //用迭代器

    尾插push_back()

    vector没有头插 / 头删(因为每次都要挪数据,效率太低),也不能用operator+=,

    它只能尾插 / 尾删,或者insert/erase。总之,就是一个一个地插入、删除。

    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. vector<int> v1;      
    6. v1.push_back(1);
    7. v1.push_back(2);
    8. v1.push_back(3);
    9. v1.push_back(4);
    10. return 0;
    11. }

    相关接口:尾删pop_back()

    vector的遍历

    先说明一下:

    vector是不能直接用流插入输出的:

    因为vector是一个容器,它可以存储多个元素。

    而流插入输出操作符<<是用于将一个单独的元素插入到流中的,而不是将整个容器插入到流中。

    因此,如果要将vector中的元素输出到流中,需要使用循环逐个输出

    现在我们就来看看遍历输出vector的4种方法:

    1.用方括号+下标 遍历:

    vector是支持operator[]和size()的,因此可以用 方括号+下标 的方式遍历。

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. vector<int> v;      
    7. v.push_back(1);
    8. v.push_back(2);
    9. v.push_back(3);
    10. v.push_back(4);
    11. for (size_t i = 0; i < v.size(); i++)
    12. {
    13. cout << v[i] << " ";
    14. }
    15. return 0;
    16. }

    2.调用at()来访问:

    at()是像函数一样调用的:

    1. for (size_t i = 0; i < v.size(); i++)
    2. {
    3. cout << v.at(i) << " ";
    4. }

    这里补充一下at()和operator[]的区别:两者检查越界的方式不一样。

    at()是较温和的抛异常:

    而operator[]是断言:

    3.用迭代器遍历

    1. vector<int>::iterator it = v.begin();
    2. while (it != v.end())
    3. {
    4. cout << *it << " ";
    5. it++;
    6. }

    4.范围for遍历:

    1. for (auto& e : v)
    2. {
    3. cout << e << " ";
    4. }

    vector的空间修改

    容量空间接口说明
    size获取数据个数
    capacity获取容量大小
    empty判断是否为空
    resize (重点)改变vector的size
    reserve (重点)改变vector的capacity

    这些接口的功能、用法都和string里的类似,就不详讲了。

    这里要说下,capacity在vs下和在g++下的增长问题:

    vs下capacity是按1.5倍增长的,g++是按2倍增长的。

    这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

    来测试下:

    vs

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. vector<int> v;  
    7. int val = v.capacity();
    8. for (size_t i = 0; i < 100; i++)
    9. {
    10. v.push_back(i);
    11. if (val != v.capacity())
    12. {
    13. cout <<"now the capacity is: "<< v.capacity() << endl;
    14. }
    15. val = v.capacity();
    16. }
    17. return 0;
    18. }

    g++:

    vector增删查改

    覆盖assign()

    assign:将新内容指定给vector,替换其当前内容,并相应地修改其size。也就是说,起到一个替换、覆盖的作用。

    演示:

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. vector<int> v;  
    7. v.push_back(1);
    8. v.push_back(2);
    9. v.push_back(3);
    10. for (auto& e : v)
    11. {
    12. cout << e << " ";
    13. }
    14. cout << endl;
    15. v.assign(8, 8);
    16. for (auto& e : v)
    17. {
    18. cout << e << " ";
    19. }
    20. return 0;
    21. }

    查找find()

    其实vector的接口里并未提供find(),不光是vector,list、deque等容器中也没有该函数。

    这是因为像vector、list、deque等容器,它们都是从头到尾遍历查找,查找逻辑是相同的。

    而在算法库中,find()是一个类模板算法,所有的容器都可以复用,想用时直接套上去用,因此没必要单独实现find()接口了。

    注意:

    1.要包头文件。

    2.迭代器区间,都是左闭右开的 :[ first,last )

    3.返回的是迭代器。如果找到了val,返回val的迭代器;如果没找到,返回last,即右边开区间的位置。

    示例:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main()
    6. {
    7. vector<int> v;  
    8. v.push_back(1);
    9. v.push_back(2);
    10. v.push_back(3);
    11. v.push_back(4);
    12. vector<int>::iterator it = find(v.begin(), v.end(), 3);
    13. cout << *it << endl;
    14. return 0;
    15. }

    插入insert()

    有了insert(),我们可以实现自由插入了,包括头插。

    现在我们就在2的前面插入一个100:

    1. int main()
    2. {
    3. vector<int> v;  
    4. v.push_back(1);
    5. v.push_back(2);
    6. v.push_back(3);
    7. vector<int>::iterator pos = find(v.begin(), v.end(), 2);   //先找到2的位置pos
    8. if (pos != v.end())
    9. {
    10. vector<int>::iterator it = v.insert(pos, 100);     //在pos位置插入100,2被挤到后一个
    11. }
    12.    
    13. for (auto& e : v)
    14. {
    15. cout << e << " ";
    16. }
    17. return 0;
    18. }

    删除erase()

    示例:

    1. int main()
    2. {
    3. vector<int> v;  
    4. v.push_back(1);
    5. v.push_back(2);
    6. v.push_back(3);
    7. v.push_back(4);
    8. vector<int>::iterator pos = find(v.begin(), v.end(), 2);
    9. if (pos != v.end())
    10. {
    11. v.erase(pos);
    12. }
    13. for (auto& e : v)
    14. {
    15. cout << e << " ";
    16. }
    17. return 0;
    18. }

    排序sort()

    sort()和find()一样,都是在中的类模板算法,可以被不同的容器复用。

    ➡️排序算法默认排的是升序,例:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main()
    6. {
    7. vector<int> v;  
    8. v.push_back(11);
    9. v.push_back(8);
    10. v.push_back(3);
    11. v.push_back(4);
    12. v.push_back(0);
    13. v.push_back(4);
    14. v.push_back(9);
    15. v.push_back(7);
    16. for (auto e : v)
    17. {
    18. cout << e << " ";
    19. }
    20. cout << endl;
    21. sort(v.begin(), v.end());
    22. for (auto e : v)
    23. {
    24. cout << e << " ";
    25. }
    26. cout << endl;
    27. return 0;
    28. }

    ➡️那要怎么排降序呢?

    用仿函数(仿函数目前不详讲,现在会用就行),库里面已经写好了,直接拿来用即可。

    1. template <class RandomAccessIterator, class Compare>  
    2. void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);   //仿函数Compare comp

    两个仿函数,一个叫less(<,升序),一个叫greater(>,降序),两个都是类模板。

    注意:在使用时要包头文件。

    示例:

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. int main()
    7. {
    8. vector<int> v;  
    9. v.push_back(11);
    10. v.push_back(8);
    11. v.push_back(3);
    12. v.push_back(4);
    13. v.push_back(0);
    14. v.push_back(4);
    15. v.push_back(9);
    16. v.push_back(7);
    17. for (auto e : v)
    18. {
    19. cout << e << " ";
    20. }
    21. cout << endl;
    22. less<int> lt;
    23. greater<int> gt;
    24. sort(v.begin(), v.end(), lt);   //升序
    25. for (auto e : v)
    26. {
    27. cout << e << " ";
    28. }
    29. cout << endl;
    30. sort(v.begin(), v.end(), gt);   //降序
    31. for (auto e : v)
    32. {
    33. cout << e << " ";
    34. }
    35. cout << endl;
    36. return 0;
    37. }

    不过,更常见的是用匿名对象来写:

    sort(v.begin(), v.end(), greater<int>()); 

    string与vector的区别

    既然vector是类模板,那vector能代替string吗?

    答案当然是不能。

    原因:

    1.string结尾是有'\0'的,而vector没有。

    2.很多string的接口,vector都用不起来,如+=、find、<<、>>、比较大小、to_string等。

    所以,几乎不会用vector,一般直接用string。

  • 相关阅读:
    JavaScript 导论
    AP1236 线性LDO稳压IC 工作原理图分享
    Linux基础内容(10)—— 进程概念
    【2-Docker安装部署ElasticSearch和Kibanan详细步骤】
    Zabbix监控组件及流程
    22-07-30 西安 MybatisPlus
    非零基础自学Java (老师:韩顺平) 第14章 集合 14.12 Map 接口和常用方法
    【Python】利用tkinter开发AI对战井字棋游戏
    【DW组队学习—Wonderful SQL】集合运算
    Linux学习笔记之设备驱动篇(3)_内核模块_实验篇
  • 原文地址:https://blog.csdn.net/2301_76540463/article/details/133417900