【C++阅览室】C++之Vector(容器)

2024-05-11 11:52
文章标签 c++ 容器 vector 阅览室

本文主要是介绍【C++阅览室】C++之Vector(容器),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

vector的介绍         

vector的使用

vector的定义

vector iterator 的使用

vector 空间增长问题

vector 增删查改

vector 迭代器失效问题。(重点)    


vector的介绍         

1、 vector 是表示可变大小数组的序列容器,可以使用连续储存空间存元素,这代表可以使用下标访问容器内的元素,和数组一样但又比数组高效,体现在可以自动控制容器大小。

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

 使用STL的三个境界:能用,明理,能扩展 ,那么下面学习vector,我们也是按照这个方法去学习


vector的使用

        vector在实际中非常的重要,在实际中我们熟悉常 见的接口就可以,下面列出了哪些接口是要重点掌握的
vector的定义
(constructor) 构造函数声明
接口说明
vector() (重点)
无参构造
vector size_type n, const value_type& val =value_type()
构造并初始化 n val
vector (const vector& x); (重点)
拷贝构造
vector (InputIterator first, InputIterator last);
使用迭代器进行初始化构造

vector iterator 的使用
iterator 的使用
接口说明
begin +
end (重点)
获取第一个数据位置的 iterator/const_iterator , 获取最后一个数据的下一个位置
iterator/const_iterator
rbegin + rend
获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位置的
reverse_iterator


//  vector的迭代器void PrintVector(const vector<int>& v)
{// const对象使用const迭代器进行遍历打印vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;
}

vector 空间增长问题
容量空间
接口说明
size
获取数据个数
capacity
获取容量大小
empty
判断是否为空
resize (重点)
改变 vector size
reserve (重点)
改变 vector capacity
capacity 的代码在 vs g++ 下分别运行会发现, vs capacity 是按 1.5 倍增长的, g++ 是按 2 倍增长的 。 这个问题经常会考察,不要固化的认为,vector 增容都是 2 倍,具体增长多少是根据具体的需求定义 的。vs PJ 版本 STL g++ SGI 版本 STL 。 reserve只负责开辟空间,如果确定知道需要用多少空间, reserve 可以缓解 vector 增容的代价缺陷问 题。resize在开空间的同时还会进行初始化,影响 size

vector 增删查改
vector 增删查改  
接口说明
push_back (重点)     
尾插
pop_back (重点)
尾删
find
查找。(注意这个是算法模块实现,不是 vector 的成员接口)
insert
position 之前插入 val
erase
删除 position 位置的数据
swap
交换两个 vector 的数据空间
operator[] (重点)
像数组一样访问

vector 迭代器失效问题。(重点)    
        迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了 封装 ,比如: vector 的迭代器就是原生态指针 T* 。因此 迭代器失效,实际就是迭代器底层对应指针所指向的 空间被销毁了,而使用一块已经被释放的空间 ,造成的后果是程序崩溃 ( 如果继续使用已经失效的迭代器, 程序可能会崩溃 )
对于 vector 可能会导致其迭代器失效的操作有:
1. 会引起其底层空间改变的操作,都有可能是迭代器失效 ,比如: resize reserve insert assign 、 push_back等。
#include <iostream>
using namespace std;
#include <vector>
int main()
{vector<int> v{1,2,3,4,5,6};auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。*/while(it != v.end()){cout<< *it << " " ;++it;}cout<<endl;return 0;
}

2. 指定位置元素的删除操作 - -erase
#include <iostream>
using namespace std;
#include <vector>
int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}
erase 删除 pos 位置元素后, pos 位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代 器不应该会失效,但是:如果pos 刚好是最后一个元素,删完之后 pos 刚好是 end 的位置,而 end 位置是 没有元素的,那么pos 就失效了。因此删除 vector 中任意位置上元素时, vs 就认为该位置迭代器失效 了。

从上述两个例子中可以看到:SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行结果定定不 对,如果it不在begin和end范围内,肯定会崩溃的。
迭代器失效解决办法:在使用前,对迭代器重新赋值即可

以上就是关于vector(容器)的使用~


 

这篇关于【C++阅览室】C++之Vector(容器)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/979456

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

c++中std::placeholders的使用方法

《c++中std::placeholders的使用方法》std::placeholders是C++标准库中的一个工具,用于在函数对象绑定时创建占位符,本文就来详细的介绍一下,具有一定的参考价值,感兴... 目录1. 基本概念2. 使用场景3. 示例示例 1:部分参数绑定示例 2:参数重排序4. 注意事项5.

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

使用C/C++调用libcurl调试消息的方式

《使用C/C++调用libcurl调试消息的方式》在使用C/C++调用libcurl进行HTTP请求时,有时我们需要查看请求的/应答消息的内容(包括请求头和请求体)以方便调试,libcurl提供了多种... 目录1. libcurl 调试工具简介2. 输出请求消息使用 CURLOPT_VERBOSE使用 C