vector

1.vector的介绍 

在C++中,vector是标准模板库(STL)中的一个动态数组类,属于<vector>头文件,如果放在c语言当中,就是我们所熟知的数组,不过,c++将其封装成了一个类,不仅能存放char类型、int类型、浮点型、甚至自定义类型等,vector也包含了许多相关的接口,因此,vector要比c语言的数组复杂许多

2.vector的使用 

 学习像vector等标准模板库的内容时,强烈建议看c++文档,vector在实际中非常的重要,在实际中熟悉常见的接口有以下部分

2.1vector的定义

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

 代码示例:

#include<vector> //使用vector需要包含此头文件
#include<iostream>
using namespace std;  //对于初学者而言建议使用此头文件,减少了空间域的展开代码

int main()
{
    vector<int> arr1(10); //创建了一个int类型的10个元素的数组arr1,未进行初始化
    vector<int> arr2(5, 5); //创建了一个int类型的5个元素的数组arr2,所有元素均初始化为5
    vector<int> arr3(arr2); //使用arr2拷贝构造了arr3
    auto it1 = arr2.begin(); //迭代器
    auto it2 = arr2.end();
    vector<int> arr4(it1, it2); //使用arr2的迭代器进行构造arr4,构造范围是it1到it2
    return 0;
}

2.2 vector iterator 的使用

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

begin 和 end 对应的是正向迭代器

rbegin 和 rend 对应的是反向迭代器 

 图解:

 代码示例:

#include<vector>
#include<iostream>
using namespace std;

int main()
{
    vector<int> arr1(10);
    for (int i = 0; i < 10; i++)
    {
        arr1[i] = i + 1;
    }
    vector<int>::iterator it = arr1.begin();
    auto it1 = arr1.begin(); //与上一行意义相同,使用auto减少了代码量

    while (it != arr1.end()) //使用正向迭代器进行遍历
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;


    auto rit = arr1.rbegin();
    while (rit != arr1.rend()) //使用反向迭代器遍历
    {
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;

    for (auto a : arr1) //使用范围for遍历,实际上底层调用的还是迭代器
    {
        cout << a << " ";
    }
}

2.3 vector 空间增长问题 

相关接口:

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

代码示例: 

#include<vector>
#include<iostream>
using namespace std;

int main()
{
    vector<int> arr(10, 1);
    cout << arr.size() << endl; //获取arr的有效元素个数
    cout << arr.capacity() << endl; //获取arr的容量
    cout << arr.empty() << endl; //判断arr是否为空

    arr.resize(8); //改变arr的有效个数,给定的值小于有效元素个数,则减小有效元素个数
    for (auto a : arr)
    {
        cout << a << " ";
    }
    cout << endl;

    arr.resize(12, 4);  //给定的值大于有效元素个数,则使用“4”进行填充,必要时会自动扩容
    for (auto a : arr)
    {
        cout << a << " ";
    }
    return 0;
}

需要了解的细节:

  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2 倍增长的
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代 价缺陷问题
  • resize在开空间的同时还会进行初始化,影响size 

 对于vector的扩容机制,c++并没有明确的规定,因此取决于编译器,如果想测试一下编译器的扩容机制,可以使用下面这段代码

#include<vector>
#include<iostream>
using namespace std;

// 测试vector的默认扩容机制
void TestVectorExpand()
{
    size_t sz;
    vector<int> v;
    sz = v.capacity();
    cout << "making v grow:\n";
    for (int i = 0; i < 100; ++i)
    {
        v.push_back(i);
        if (sz != v.capacity())
        {
            sz = v.capacity();
            cout << "capacity changed: " << sz << '\n';
        }
    }
}

int main()
{
    TestVectorExpand();
    return 0;
}

在VS2022下运行: 

 

可以明显看出,这里是按1.5倍进行扩容的 

2.4 vector 增删查改  

vector增删查改接口说明
push_back(重点)尾插
pop_back(重点)尾删
find查找(算法模块实现,非vector成员接口)
insert在position之前插入value
eraser删除position位置的数据
swap交换两个vector的数据空间
operator[](重点)像数组一样访问其元素

代码示例:

#include<vector>
#include<iostream>
using namespace std;

int main()
{
    vector<int> arr(0); //创建一个空数组
    arr.push_back(1);  //尾插数据"1"
    arr.push_back(2);
    arr.push_back(3);
    arr.push_back(4);
    arr.push_back(5);

    for (auto a : arr)
    {
        cout << a << " ";
    }
    cout << endl;

    arr.pop_back();  //尾删数据
    
    for (auto a : arr)
    {
        cout << a << " ";
    }
    //for (int i = 0; i < 4; i++)  //像数组一样访问
    //{
    //    cout << arr[i] << " ";
    //}

    auto it1 = arr.begin();  //迭代器
    it1 = arr.insert(it1, 3); //向it1位置插入数据并修正it1,防止迭代器失效
    for (auto a : arr)
    {
        cout << a << " ";
    }
    cout << endl;
    arr.erase(it1);  //删除it位置的数据,position就是这里的it,是一个迭代器
    for(auto a : arr)
    {
        cout << a << " ";
    }

    it1 = arr.begin();
    auto it2 = arr.end();
    auto it3 = find(it1, it2, 2); //在迭代器 it1 到 it2 的这段区间内查找“2”
    cout << *it3 << endl;

    vector<int> arr1(3, 0);
    swap(arr, arr1);  //交换两个vector空间的数据
    for (auto a : arr)
    {
        cout << a << " ";
    }
    cout << endl;

    for (auto a : arr1)
    {
        cout << a << " ";
    }
    return 0;
}

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

在上面的2.4中,有一行代码是这样写的:

it1 = arr.insert(it1, 3);

这个接口自己提供了返回值,那为什么要提供返回值?

如果不提供返回值,没有修正it1,此时的it1已经不是指向之前那个元素了,如果此时使用it1,很有可能造成错误,而且这个错误有可能很难发现,(gcc下,不报错,vs严格检查,此时会报错) 

因此,修正迭代器是非常有必要的,这就涉及迭代器失效问题了 

 1.失效原因

会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、 assign、push_back等,为什么是有可能,原因之一是vector的自动扩容我们不知道什么时候会发生,以及上面所说的问题

#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.解决方法 

解决方法很简单,就是在使用前对迭代器重新赋值 

05-29
C++ 中,vector 是一个动态数组容器,可以存储任意类型的数据。使用 vector 可以方便地进行动态内存分配和管理,而不需要手动进行内存分配和释放。 vector 提供了一系列的成员函数,可以方便地进行元素的插入、删除、查找和访问等操作。以下是一些常用的操作: 1. 创建 vector 对象: ```c++ #include <vector> std::vector<int> vec; // 创建一个空的 vector std::vector<int> vec1(10); // 创建一个包含 10 个默认值的 vector std::vector<int> vec2(10, 0); // 创建一个包含 10 个值为 0 的 vector std::vector<int> vec3 = {1, 2, 3, 4}; // 创建一个包含 4 个元素的 vector,初始值为 1, 2, 3, 4 std::vector<int> vec4(vec3); // 创建一个与 vec3 完全相同的新 vector ``` 2. 访问 vector 中的元素: ```c++ std::vector<int> vec = {1, 2, 3, 4}; std::cout << vec[0] << std::endl; // 访问第一个元素,输出 1 std::cout << vec.at(2) << std::endl; // 访问第三个元素,输出 3 std::cout << vec.front() << std::endl; // 访问第一个元素,输出 1 std::cout << vec.back() << std::endl; // 访问最后一个元素,输出 4 ``` 3. 插入和删除元素: ```c++ std::vector<int> vec = {1, 2, 3, 4}; vec.push_back(5); // 在末尾插入元素 5 vec.insert(vec.begin() + 2, 10); // 在第三个位置插入元素 10 vec.erase(vec.begin() + 1); // 删除第二个元素 ``` 4. 获取 vector 中的信息: ```c++ std::vector<int> vec = {1, 2, 3, 4}; std::cout << vec.size() << std::endl; // 输出 vector 的大小,即元素个数,输出 4 std::cout << vec.empty() << std::endl; // 判断 vector 是否为空,输出 0(因为不为空) ``` vector 还提供了一些其他的函数,如排序、反转、查找等,具体可以参考 C++ 标准库的文档。
评论 45
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值