• 【深入理解C++】vector


    1.概述

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

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

    2.vector的定义与初始化

    头文件 include

    #include 
    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

    #include 
    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.vector的赋值

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.vector的元素个数

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

    #include 
    #include 
    
    using namespace std;
    
    int main()
    {
        vector<int> v{10, 20, 30, -10, -20, -30};
    
        cout << v.size() << endl; // 6
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

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

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    6.判断两个vector是否相等

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    7.vector的遍历

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

    7.1 [ ] 运算符

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.2 at()

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.3 范围for

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    7.4 迭代器iterator

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

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

    vector<typename>::iterator iter;
    
    • 1

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    7.4.1 begin()与end()

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

    7.4.2 front()与back()

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    7.5 反向迭代器reverse_iterator

    7.5.1 rbegin()与rend()

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.6 常量迭代器const_iterator

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

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

    #include 
    #include 
    
    using namespace std;
    
    int main()
    {
        vector<int> v = {100, 200, 300}; // 非const容器
        const vector<int>::iterator iter = v.begin();
        *iter = 4; // 正确
        iter++; // 错误
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7.6.1 cbegin()与cend()

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    Chapter5.1:线性系统的频域分析法
    Cesium 报错:TypeError: Cesium.MeasurementTool is not a constructor
    CVE-2020-1472-ZeroLogon复现
    记一次 CDN 流量被盗刷经历
    java经典代码
    mysql数据库 操作常用命令
    2022 年牛客多校第九场补题记录
    l8-d8 TCP并发实现
    RadiantQ jQuery甘特图,资源分配单元计算的支持
    mybatis标签详解,一篇就够了
  • 原文地址:https://blog.csdn.net/qq_42815188/article/details/87928740