【深入理解C++】vector

1.概述

vector 翻译为“向量”,也可称为“变长数组”,即“长度根据需要而自动改变的数组”。

vector 动态增长的原理:当插入新元素的时候,如果空间不足,那么 vector 会重新申请更大的一块内存空间,将原空间数据拷贝到新空间,释放旧空间,再把新元素插入到新申请空间。

2.vector的定义与初始化

头文件 include <vector>

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    vector<int> v1; // int类型的空vector
    vector<string> v2; // string类型的空vector

    vector<int> v3(20, -10); // 创建20个int类型的元素,每个元素的值为-10
    vector<string> v4(15, "hello"); // 创建15个string类型的元素,每个元素的值为hello

    vector<int> v5(20); // 创建20个int类型的元素,每个元素值默认为0
    vector<string> v6(15); // 创建15个string类型的元素,每个元素值默认为空串

    vector<int> v7(v3); // 通过拷贝构造函数初始化
    vector<string> v8 = v4; // 通过拷贝构造函数初始化
    
    vector<int> v9(v3.begin(), v3.end());
    
    return 0;
}

在 C++11 标准中,可以用列表初始化方法给值,即用 {} 括起来。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    vector<int> v1(10); // 创建10个int类型的元素,每个元素值为0
    vector<int> v2{10}; // 创建1个int类型的元素,该元素的值为10

    vector<int> v3(10, 1); // 创建10个int类型的元素,每个元素值为1
    vector<int> v4{10, 1}; // 创建2个int类型的元素,元素值分别为10和1

    vector<string> v5 = {"aaa", "bbb", "ccc"};

    vector<string> v6(10); // 创建10个string类型的元素,每个元素值默认为空串
    vector<string> v7{10}; // 创建10个string类型的元素,每个元素值默认为空串

    vector<string> v8(10, "hello"); // 创建10个string类型的元素,每个元素值默认为hello
    vector<string> v9{10, "hello"}; // 创建10个string类型的元素,每个元素值默认为hello

    return 0;
}

3.vector的赋值

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v1;
    v1.assign(5, 1); // 将5个1赋值给v1

    vector<int> v2;
    v2.assign(v1.begin(), v1.end()); // 将v1的[begin,end)赋值给v2

    vector<int> v3;
    v3 = v1;

    return 0;
}

4.vector的元素个数

size() 用来获得 vector 中元素的个数,时间复杂度为 O ( 1 ) O(1) O(1)

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v{10, 20, 30, -10, -20, -30};

    cout << v.size() << endl; // 6

    return 0;
}

5.vector尾部添加或删除元素

push_back(x) 就是在 vector 后面添加一个元素 x,时间复杂度为 O ( 1 ) O(1) O(1)

pop_back() 用以删除 vector 的最后一个元素,时间复杂度为 O ( 1 ) O(1) O(1)

vector 在尾部添加或删除元素非常快。在中间操作非常耗时,因为它需要移动元素。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;

    v.push_back(11);
    v.push_back(22);
    v.push_back(33);

    v.pop_back();

    cout << v.size() << endl; // 2

    return 0;
}

6.判断两个vector是否相等

如果两个 vector 的元素数量相等并且对应位置的元素值也相等,那么这两个 vector 就相等,否则不相等。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v1 = {100, 200, 300, -10, -20, -30};
    vector<int> v2 = {100, 200, 300, -1, -2, -3};

    if (v1 == v2)
    {
        cout << "v1 == v2" << endl;
    }
    else
    {
        cout << "v1 != v2" << endl;
    }

    return 0;
}

7.vector的遍历

vector 容器可以随机存取元素。

7.1 [ ] 运算符

和访问普通数组一样,对于 vector 容器来说,直接访问 v[index] 即可。当然,这里的下标 index 是从 0v.size()-1,访问这个范围外的元素可能会运行出错。

[] 方式,如果越界或出现其他错误,不会抛出异常,可能崩溃,可能数据随机出现。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v{10, 20, 30, -10, -20, -30};

    for (int i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }       
    cout << endl;

    return 0;
}

7.2 at()

at() 方式,如果越界或出现其他错误,会抛出异常,需要捕获异常并处理。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v{10, 20, 30, -10, -20, -30};

    for (int i = 0; i < v.size(); i++)
    {
        cout << v.at(i) << " ";
    }
    cout << endl;

    return 0;
}

7.3 范围for

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v = {100, 200, 300, -10, -20, -30};

    for (auto &x : v)
    {
        x *= 2;
    }

    for (auto &x : v)
    {
        cout << x << endl;
    }

    return 0;
}

7.4 迭代器iterator

迭代器可以理解为一种类似于指针的东西,通过迭代器我们可以读容器中的元素值,还可以修改某个迭代器所指向的元素值。

迭代器的定义如下,iter 就是一个 vector<typename>::iterator 类型的变量,其中 typename 就是定义 vector 时所填写的类型。

vector<typename>::iterator iter;

v[i]*(v.begin()+i) 是等价的。需要注意的是,在常用 STL 容器中,只有在 vector 和 string 中,才允许使用 v.begin()+i 这种迭代器加上整数的写法。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v{10, 20, 30, -10, -20, -30};

    vector<int>::iterator iter = v.begin();

    for (int i = 0; i < v.size(); i++)
    {
        cout << *(iter + i) << " ";
    }
    cout << endl;

    return 0;
}

7.4.1 begin()与end()

begin() 返回的迭代器指向容器中的第一个元素。

end() 返回的迭代器指向容器中的最后一个元素的下一个位置。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<char> v1;
    v1.push_back('h');
    v1.push_back('e');
    v1.push_back('l');
    v1.push_back('l');
    v1.push_back('o');
    
    vector<char>::iterator iter1 = v1.begin();
    cout << *iter1 << endl;
    
    vector<char>::iterator iter2 = v1.end() - 1;
    cout << *iter2 << endl;
    
    return 0;
}

如果一个容器为空,则 begin() 和 end() 返回的迭代器相同。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<char> v;
    vector<char>::iterator iter1 = v.begin();
    vector<char>::iterator iter2 = v.end();
    if (iter1 == iter2)
    {
        cout << "容器v为空" << endl;
    }

    return 0;
}

迭代器支持自增、自减操作,于是可以通过如下代码遍历 vector 中的元素。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v{10, 20, 30, -10, -20, -30};

    for (vector<int>::iterator iter = v.begin(); iter != v.end(); iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    return 0;
}

注意:在使用迭代器的过程中,千万不要改变 vector 容器的容量(不要增加或删除 vector 容器中的元素),否则迭代器会失效。

7.4.2 front()与back()

front() 返回头部元素的引用,可以当左值。

back() 返回尾部元素的引用,可以当左值。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<char> v1;
    v1.push_back('h');
    v1.push_back('e');
    v1.push_back('l');
    v1.push_back('l');
    v1.push_back('o');

    cout << "v1.front() = " << v1.front() << endl;
    cout << "v1.back() = " << v1.back() << endl;

    v1.front() = 'w';
    v1.back() = 'd';
    
    cout << "v1.front() = " << v1.front() << endl;
    cout << "v1.back() = " << v1.back() << endl;

    return 0;
}

在这里插入图片描述

7.5 反向迭代器reverse_iterator

7.5.1 rbegin()与rend()

rbegin() 返回一个反向迭代器,指向反向迭代器的第一个元素。

rend() 返回一个反向迭代器,指向反向迭代器的最后一个元素的下一个位置。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v{10, 20, 30, -10, -20, -30};
    
    for (vector<int>::reverse_iterator riter = v.rbegin(); riter != v.rend(); riter++)
    {
        cout << *riter << endl;
    }

    return 0;
}

7.6 常量迭代器const_iterator

vector<int>::iterator iter 可以修改指针的地址,也可以修改指向的元素值。

vector<int>::const_iterator iter 相当于 const char *p,可以修改指针的地址,但不能修改指向的元素值。const_iterator 对象可以用于 const容器 或 非const容器。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    const vector<int> v1 = {100, 200, 300}; // const容器
    vector<int>::const_iterator iter1 = v1.begin(); // vector本身是const类型,其迭代器也是const类型
    *iter1 = 4; // 错误
    iter1++; // 正确

    vector<int> v2 = {100, 200, 300}; // 非const容器
    vector<int>::const_iterator iter2 = v2.begin(); // vector本身是非const类型,其迭代器也是非const类型
    *iter2 = 4; // 错误
    iter2++; // 正确

    return 0;
}

const vector<int>::iterator iter 相当于 char * const p,可以修改指向的元素值,但不能修改指针的地址。const 的 iterator 只能用于 非const 容器。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v = {100, 200, 300}; // 非const容器
    const vector<int>::iterator iter = v.begin();
    *iter = 4; // 正确
    iter++; // 错误

    return 0;
}

7.6.1 cbegin()与cend()

C++11 引入了两个新函数:cbegin() 和 cend() 返回的都是常量迭代器。

如果容器本身不是 const 类型,但是在某些情况下数据不应该被修改,这时可以通过 cbegin() 和 cend() 返回 const 类型的迭代器,以避免数据被意外修改。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v = {100, 200, 300}; // 非const容器

    for (vector<int>::const_iterator iter = v.cbegin(); iter != v.cend(); iter++)
    {
        *iter = 4; // 错误
        cout << *iter << endl;
    }

    return 0;
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值