【十一】【C++】vector类常见用法

std::vector是C++标准模板库(STL)中提供的一种序列容器,可以存储任意类型的对象(通过模板参数指定),对象存储在连续的内存空间中。vector提供了动态数组的功能,但比普通数组更灵活、更安全。以下是std::vector的一些主要使用方法:

头文件

要使用std::vector,需要包含头文件


#include 

创建对象


std::vector vec; // 创建一个空的int类型vector
std::vector vec2(10); // 创建一个包含10个初始化为0的int元素的vector
std::vector vec3(10, 1); // 创建一个包含10个初始化为1的int元素的vector
std::vector vec4{1, 2, 3, 4, 5}; // 列表初始化
std::vector vec5(vec4.begin(), vec4.end()); // 范围初始化
std::vector vec6(vec4); // 拷贝初始化

空初始化

std::vector vec;

这行代码创建了一个类型为 int 的空 vector。初始时,它不包含任何元素。

默认值初始化

std::vector vec2(10);

创建一个包含 10 个元素的 vector,每个元素都被初始化为 int 类型的默认值,即 0。这种初始化方式在你想要一个特定大小的 vector,但所有元素初始值相同(并且是该类型的默认值)时非常有用。

显式值初始化

std::vector vec3(10, 1);

创建一个包含 10 个元素的 vector,每个元素都初始化为 1。这允许你创建一个具有初始非默认值的 vector

列表初始化

std::vector vec4{1, 2, 3, 4, 5};

使用花括号 {} 包含的列表直接初始化 vector。这里,vec4 被初始化为包含五个元素 1, 2, 3, 4, 5 的 vector。这种方式非常直观,适用于当你已知所有初始元素时。

范围初始化

std::vector vec5(vec4.begin(), vec4.end());

通过另一个 vector vec4 的迭代器范围来初始化 vec5。这种初始化方式创建了一个新的 vector,它包含了原 vector vec4 中所有元素的拷贝。这适用于当你需要从现有容器的一部分或全部创建一个新容器时。

拷贝初始化

std::vector vec6(vec4);

直接使用另一个 vector vec4 来初始化 vec6vec6 将包含 vec4 的所有元素的拷贝。这种方式创建了一个完全相同的 vector 副本。

访问元素

std::vector vec4{1, 2, 3, 4, 5}; // 列表初始化


std::cout << vec4[2]; // 使用下标访问,不检查范围
std::cout << vec4.at(2); // 使用at方法访问,会检查范围
std::cout << vec4.front(); // 访问第一个元素
std::cout << vec4.back(); // 访问最后一个元素

使用下标访问

std::cout << vec4[2];

这行代码使用下标操作符 [] 来访问 vec4 中下标为 2 的元素(即第三个元素),并将其输出。在 vec4 的情况下,这将输出 3。下标操作符不执行范围检查,如果你尝试访问一个越界的下标,结果是未定义的,可能导致运行时错误。

使用 at 方法访问

std::cout << vec4[2];

使用 at 成员函数来访问 vec4 中下标为 2 的元素,并将其输出。at 方法与下标操作符不同,它会检查给定的下标是否在 vector 的范围内。如果下标越界(即下标大于或等于 vector 的大小),at 方法会抛出一个 std::out_of_range 异常。在 vec4 的情况下,这同样会输出 3

访问第一个元素

std::cout << vec4.front();

这行代码使用 front 方法获取 vec4 的第一个元素并输出它。对于 vec4front() 返回 1

访问最后一个元素

std::cout << vec4.front();

使用 back 方法来访问并输出 vec4 的最后一个元素。对于 vec4back() 返回 5

修改操作

std::vector vec4{1, 2, 3, 4, 5}; // 列表初始化


vec4.push_back(6); // 在尾部添加一个元素
vec4.pop_back(); // 移除尾部元素
vec4.insert(vec4.begin() + 2, 42); // 在指定位置插入元素
vec4.erase(vec4.begin() + 2); // 删除指定位置的元素
vec4.clear(); // 清除所有元素

在尾部添加一个元素

vec4.push_back(6);

这行代码在 vec4 的末尾添加一个元素 6。在执行这个操作之后,vec4 的内容变为 {1, 2, 3, 4, 5, 6}

移除尾部元素

vec4.pop_back();

该操作移除 vec4 中的最后一个元素。如果在执行了上一个 push_back(6) 操作之后立即执行此操作,vec4 将恢复到 {1, 2, 3, 4, 5}

在指定位置前面插入元素

vec4.insert(vec4.begin() + 2, 42);

这行代码在 vec4 的第三个位置(即下标为 2 的位置,vector 下标从 0 开始)前面插入元素 42。在此操作之后,如果 vec4 原先为 {1, 2, 3, 4, 5},那么它现在将变为 {1, 2, 42, 3, 4, 5}

删除指定位置的元素

vec4.erase(vec4.begin() + 2);

这个操作删除 vec4 中下标为 2 的元素,即在上一步中刚插入的 42。在此操作之后,vec4 将恢复到插入 42 之前的状态,变为 {1, 2, 3, 4, 5}(假设之前已经插入了 42)。

清除所有元素

vec4.clear();

这行代码移除 vec4 中的所有元素,使其变为空 vector。执行这个操作之后,vec4.size() 将返回 0,表示 vec4 不包含任何元素。

大小和容量

std::vector vec4{1, 2, 3, 4, 5}; // 列表初始化


std::cout << vec4.size(); // 返回vector中元素的数量
std::cout << vec4.capacity(); // 返回vector的容量
std::cout << vec4.empty(); // 检查vector是否为空
vec4.resize(10); // 改变vector中元素的数量
vec4.resize(10,5); // 改变vector中元素的数量
vec4.reserve(20); // 改变vector的容量

查询 vector 中元素的数量

std::cout << vec4.size();

size() 成员函数返回 vector 当前包含的元素数量。例如,如果 vec4 当前包含 {1, 2, 3, 4, 5},则 vec4.size() 将返回 5

查询 vector 的容量

std::cout << vec4.capacity();

capacity() 成员函数返回 vector 在需要重新分配内存之前可以容纳的元素数量。这是由于 vector 的内部实现会预留一定的空间以减少因增加元素而频繁重新分配内存的需要。

检查 vector 是否为空

std::cout << vec4.empty();

empty() 成员函数检查 vector 是否不包含任何元素。如果 vector 为空,则返回 true;否则返回 false

改变 vector 中元素的数量(size)

vec4.resize(10);

resize(n) 调整 vector 的大小以包含 n 个元素。如果 n 大于当前的 size(),则新增的元素会被默认初始化(对于整数类型,这通常意味着初始化为 0)。 vec4.resize(10, 5);

这个 resize(n, val) 的重载版本不仅改变 vector 的大小使之包含 n 个元素,如果 n 大于当前大小,还会用 val 初始化新增的元素。在这个例子中,如果 vec4 的大小被扩展到 10 个元素,新添加的元素将被初始化为 5

改变 vector 的容量(capacity

vec4.reserve(20);

reserve(n) 成员函数请求改变 vector 的容量至少为 n。这个操作可以减少因增加元素而导致的内存重新分配的次数。如果 n 小于或等于当前的容量,这个操作不会有任何效果。reserve 不会改变 vector 的大小(即包含的元素数量)。

迭代器

std::vector vec4{1, 2, 3, 4, 5}; // 列表初始化


for (auto it = vec4.begin(); it != vec4.end(); ++it) {
    std::cout << *it << " ";
}
for (auto rit = vec4.rbegin(); rit != vec4.rend(); ++rit) {
    std::cout << *rit << " ";
}

正向遍历 for (auto it = vec4.begin(); it != vec4.end(); ++it) { std::cout << *it << " "; }

这里,it 是一个迭代器,初始化为 vec4 的开始(begin() 返回一个指向容器第一个元素的迭代器)。循环持续进行,直到迭代器 it 等于 vec4.end()end() 返回一个指向容器最后一个元素之后位置的迭代器,不是最后一个元素本身)。

在每次循环中,通过解引用迭代器 *it 来访问当前元素,并输出该元素值,然后迭代器通过 ++it 自增,移向下一个元素。

这种方式按顺序遍历 vector 中的所有元素。

反向遍历 for (auto rit = vec4.rbegin(); rit != vec4.rend(); ++rit) { std::cout << *rit << " "; }

这里使用了反向迭代器 ritrbegin() 返回一个指向容器最后一个元素的反向迭代器(即逻辑上的“开始”),而 rend() 返回一个指向容器第一个元素之前位置的反向迭代器(逻辑上的“结束”)。

循环以相似的方式进行,不过这次是从容器的末尾开始,通过每次自增迭代器(在反向迭代器的上下文中,自增实际上是向前移动)来逆序遍历容器中的所有元素。

这种方式按照逆序遍历 vector 中的所有元素。

特殊成员函数

std::vector vec4{1, 2, 3, 4, 5}; // 列表初始化 std::vector vec5(vec4.begin(), vec4.end()); // 范围初始化 std::vector vec6(vec4); // 拷贝初始化


vec4.assign(5, 10); // 将vector中的内容替换为5个10
vec5.assign(array, array + sizeof(array) / sizeof(array[0]));//array数组中,0位置到结尾,替换掉vec5的内容
vec7.swap(vec4); // 交换两个vector的内容

使用 assign 方法替换 vector 的内容

vec4.assign(5, 10);

assign(n, val) 成员函数将 vec4 的内容替换为 n 个重复的 val 值。在这个例子中,vec4 的内容被替换为 5 个值为 10 的整数。如果 vec4 之前包含任何元素,这些元素会被销毁。

vec5.assign(array, array + sizeof(array) / sizeof(array[0]));

这个 assign 的重载版本接受两个迭代器作为参数,用来指定一个范围。这里使用了从数组 array 的开始到结束的范围,将 vec5 的内容替换为 array 中的元素。假设 array 是之前定义的整型数组 {1, 2, 3, 4, 5},则 vec5 将包含这些值。

交换两个 vector 的内容

vec7.swap(vec4);

swap 成员函数交换两个 vector 的内容。在这个例子中,vec7vec4 的内容被交换。

vector常见用法的探究


#include 
#include 
using namespace std;
void TestVector1() {
    vector v1;
    vector v2(10, 5);

    int array[] = { 1, 2, 3, 4, 5 };
    vector v3(array, array + sizeof(array) / sizeof(array[0]));

    vector v4(v3);

    // C++11
    vector v5{ 1, 2, 3, 4, 5 };


    // vector的遍历
    // 1. for+下标
    for (size_t i = 0; i < v2.size(); ++i)
        cout << v2[i] << " ";
    cout << endl;

    // 2. 范围for
    for (auto e : v3)
        cout << e << " ";
    cout << endl;

    // 3. 正向迭代器
    vector::iterator it = v4.begin();
    while (it != v4.end()) {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // 4. 反向迭代器
    // vector::reverse_iterator rit = v5.rbegin();
    auto rit = v5.rbegin();
    while (rit != v5.rend()) {
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
 }

/*
 void resize(size_t newsize, const T& val = T())
 假设当前对象的元素个数为oldsize,底层空间大小为capacity
 1.  oldsize < newsize < capacity
 不需要扩容,直接在vector末尾填充newsize-oldsize个置为val的元素
 newsize > capacity
 扩容---在vecot总能填充newsize-oldsize个置为val的元素
 2. newsize < oldsize 直接将有效元素个数缩减到newsize
 */
void TestVector2() {
    vector v{ 1, 2, 3, 4, 5 };
    v.reserve(10);
    cout << v.size() << endl;
    cout << v.capacity() << endl;

    v.resize(8, 6);
    cout << v.size() << endl;
    cout << v.capacity() << endl;

    v.resize(20, 7);
    cout << v.size() << endl;
    cout << v.capacity() << endl;

    v.resize(10);
    cout << v.size() << endl;
    cout << v.capacity() << endl;

    v.resize(3);
    cout << v.size() << endl;
    cout << v.capacity() << endl;
 }

class A {
    public:
        A()
            : _a()
        {}

        int _a;
 };

int main() {
    vector> vv(5);
    TestVector1();
    TestVector2();
    return 0;
 }

TestVector1 函数

展示了 std::vector 的多种初始化方法:

默认构造函数 v1 创建一个空的 vector

v2 通过构造函数创建一个包含 10 个元素的 vector,每个元素初始化为 5。

v3 使用数组的首尾迭代器进行初始化,包含数组 array 的元素。

拷贝构造函数 v4vector v3 进行初始化。

列表初始化 v5 使用了 C++11 引入的初始化列表。

展示了四种遍历 vector 的方法:

使用下标遍历 v2

使用范围 for 循环遍历 v3

使用正向迭代器遍历 v4

使用反向迭代器遍历 v5

TestVector2 函数

展示了 vector 的容量管理和调整大小的方法:

初始状态下,v 包含 5 个元素。

调用 reserve(10),扩展 v 的容量至少可以容纳 10 个元素。

通过 resize(8, 6) 增加 v 的大小到 8,新增的元素初始化为 6。

再次通过 resize(20, 7) 增加 v 的大小到 20,新增的元素初始化为 7,这一步涉及到扩容。

resize(10) 减少 v 的大小到 10,如果 resize 的新大小小于当前大小,超出部分的元素会被删除。

最后 resize(3)v 的大小减少到 3。

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

你可能感兴趣的:(c++,算法)