c++——vector容器详解

vector概述

C++ 中的 std::vector 是一个动态数组,是标准模板库(STL)中的一个重要容器。它提供了动态大小、快速随机访问和插入/删除操作的能力,使其成为处理动态数据集合的常用选择。

vector——向量

向量是表示大小可以变化的数组的序列容器。

就像数组一样,向量对其元素使用连续的存储位置,这意味着也可以使用指向其元素的规则指针上的偏移量来访问其元素,并且与在数组中一样有效。但与数组不同的是,它们的大小可以动态变化,容器会自动处理它们的存储。

在内部,向量使用动态分配的数组来存储其元素。当插入新元素时,可能需要重新分配此数组才能增大大小,这意味着分配一个新数组并将所有元素移动到其中。就处理时间而言,这是一项相对昂贵的任务,因此,每次将元素添加到容器中时,向量都不会重新分配。

取而代之的是,矢量容器可能会分配一些额外的存储空间来适应可能的增长,因此容器的实际容量可能大于严格需要的存储空间来容纳其元素(即其大小)。库可以实施不同的增长策略,以在内存使用和重新分配之间取得平衡,但在任何情况下,重新分配都应该只在对数增长的大小间隔内发生,以便可以在向量末尾插入单个元素时提供摊销的常数时间复杂度(参见 push_back)。

因此,与数组相比,向量消耗更多的内存,以换取管理存储和以有效方式动态增长的能力。

与其他动态序列容器(deques、lists 和 forward_lists)相比,向量非常有效地访问其元素(就像数组一样),并且相对有效地从其末端添加或删除元素。对于涉及在末端以外的位置插入或删除元素的操作,它们的性能比其他操作差,并且迭代器和引用的一致性不如列表和forward_lists。<官网翻译来>

主要特点和优势:

动态大小: std::vector 可以根据需要动态增长或缩小其大小,这意味着可以在运行时动态地分配内存来存储其元素。

随机访问: 支持使用索引(类似数组下标)进行快速随机访问。这是通过指针算术来实现的,因此访问元素的时间复杂度为 O(1)。

尾部插入/删除: 在尾部进行元素的插入和删除操作非常高效,时间复杂度为平均 O(1)。

内存管理: std::vector 负责管理其内部存储空间的分配和释放,这使得使用起来更为方便,不需要手动管理内存。

连续存储: std::vector 的元素在内存中是连续存储的,这有助于提高缓存命中率,从而提升访问效率。

迭代器支持: 提供了迭代器(iterator)接口,可以用于遍历容器中的元素。

标准库支持: 是 C++ 标准库提供的一部分,因此具有广泛的兼容性和可移植性。

使用示例:

#include <vector>
#include <iostream>

int main() {
    // 创建一个空的vector
    std::vector<int> vec;

    // 向vector中添加元素
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    // 访问vector中的元素
    std::cout << "Elements in vector:";
    for (size_t i = 0; i < vec.size(); ++i) {
        std::cout << " " << vec[i];
    }
    std::cout << std::endl;

    // 使用迭代器进行遍历
    std::cout << "Elements in vector (using iterator):";
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << " " << *it;
    }
    std::cout << std::endl;

    return 0;
}

在上面的示例中,std::vector 被用来存储整数,并展示了如何向其中添加元素、通过索引访问元素以及使用迭代器遍历元素。

成员类型

1,value_type:

  • std::vector::value_type 表示存储在 vector 中的元素的类型。
  • 例如,如果 std::vector 则 value_type 就是 int。
  • 这个类型通常是通过模板参数 T 来确定的。

2,reference:

  • std::vector::reference 表示对 vector 中元素的引用类型。
  • 例如,如果 std::vector 则 reference 就是 int&。
  • 通过这种引用类型,可以直接修改 vector 中的元素。

3,const_reference:

  • std::vector::const_reference 表示对 vector 中元素的常量引用类型。
  • 例如,如果 std::vector 则 const_reference 就是 const int&。
  • 这种类型允许读取但不允许修改 vector 中的元素。

4,iterator 和 const_iterator:

  • std::vector::iterator 表示 vector 中元素的迭代器类型,可以用来遍历和修改 vector 中的元素。
  • std::vector::const_iterator 则是对应的常量迭代器类型,只能用于读取元素,不能修改。
  • 例如,std::vector::iterator 和 std::vector::const_iterator 分别用于 std::vector 的可变和不可变遍历。

5,difference_type:

  • std::vector::difference_type 表示两个迭代器之间的距离类型。
  • 这个类型通常是 std::ptrdiff_t,用于计算迭代器之间的距离。

6,size_type:

  • std::vector::size_type 表示 vector 中元素数量的无符号整数类型。
  • 这个类型通常是 std::size_t,用于表示 vector 中元素的数量。

vector函数

构造函数

1,默认构造函数:

std::vector<int> vec; // 创建一个空的 int 类型的 vector
//构造一个空的 vector,不包含任何元素。

2,指定大小和初值构造函数:

std::vector<int> vec(5, 10); // 创建包含 5 个元素,每个元素都是 10 的 int 类型的 vector
//创建一个包含指定数量元素的 vector,每个元素的值都是指定的初值。

3,通过迭代器范围构造函数:

std::vector<int> vec(otherVec.begin(), otherVec.end()); // 通过迭代器范围构造 vector
//使用另一个容器 otherVec 的迭代器范围 [begin, end) 构造 vector。

4,复制构造函数:

std::vector<int> vec(otherVec); // 使用另一个 vector `otherVec` 进行复制构造
//创建一个新的 vector,内容与 otherVec 相同。

5,移动构造函数:

std::vector<int> vec(std::move(otherVec)); // 移动构造,将 `otherVec` 的内容移动到新的 vector
//创建一个新的 vector,并通过移动 otherVec 的内容来构造。

6,初始化列表构造函数(C++11 引入):

std::vector<int> vec = {1, 2, 3, 4, 5}; // 使用初始化列表构造 vector
//使用大括号 {} 内的值初始化 vector,适用于 C++11 及以后的版本。

7,构造指定数量的默认值(C++11 引入):

std::vector<int> vec(10); // 创建包含 10 个默认值(0)的 int 类型的 vector
//创建一个包含指定数量元素的 vector,每个元素都是该类型的默认值。

8,构造并移动元素(C++17 引入):

std::vector<std::unique_ptr<int>> vec;
vec.emplace_back(new int(42)); // 直接在 vector 尾部构造一个新元素,避免额外的复制或移动操作
//在 vector 的尾部直接构造一个新元素,避免额外的复制或移动开销。

迭代器函数

begin() 和 end():

  • begin() 返回指向第一个元素的迭代器。
  • end() 返回指向最后一个元素之后位置的迭代器。
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin(); // 指向第一个元素的迭代器
auto endIt = vec.end(); // 指向最后一个元素之后位置的迭代器

cbegin() 和 cend():

  • cbegin() 返回指向第一个元素的常量迭代器。
  • cend() 返回指向最后一个元素之后位置的常量迭代器。
std::vector<int> vec = {1, 2, 3, 4, 5};
auto cit = vec.cbegin(); // 指向第一个元素的常量迭代器
auto cendIt = vec.cend(); // 指向最后一个元素之后位置的常量迭代器

rbegin() 和 rend():

  • rbegin() 返回指向最后一个元素的反向迭代器。
  • rend() 返回指向第一个元素之前位置的反向迭代器。
std::vector<int> vec = {1, 2, 3, 4, 5};
auto rit = vec.rbegin(); // 指向最后一个元素的反向迭代器
auto rendIt = vec.rend(); // 指向第一个元素之前位置的反向迭代器

crbegin() 和 crend():

  • crbegin() 返回指向最后一个元素的常量反向迭代器。
  • crend() 返回指向第一个元素之前位置的常量反向迭代器。
std::vector<int> vec = {1, 2, 3, 4, 5};
auto crit = vec.crbegin(); // 指向最后一个元素的常量反向迭代器
auto crendIt = vec.crend(); // 指向第一个元素之前位置的常量反向迭代器

advance():

  • advance(it, n) 将迭代器 it 向前或向后移动 n 个位置。
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin();
std::advance(it, 3); // it 现在指向 vec 中的第四个元素(索引为 3)

distance():

  • distance(first, last) 计算从 first 到 last 之间的元素个数(距离)。
std::vector<int> vec = {1, 2, 3, 4, 5};
auto dist = std::distance(vec.begin(), vec.end()); // dist 等于 5

size和capacity函数

这些函数都是 std::vector 的成员函数,用于管理其内存和大小。让我们逐个介绍它们:

size()

  • size() 是 std::vector 的公有成员函数,返回当前 std::vector 中元素的数量。
std::vector<int> vec = {1, 2, 3};
std::cout << "Size of vec: " << vec.size() << std::endl; // 输出 3

max_size()

  • max_size() 是 std::vector 的公有成员函数,返回 std::vector 可以包含的最大元素数量,这取决于系统的限制。
std::vector<int> vec = {1, 2, 3};
std::cout << "Max size of vec: " << vec.max_size() << std::endl; // 输出 std::vector 可以容纳的最大元素数量

resize(size_type n)

  • resize(n) 是 std::vector 的公有成员函数,改变 std::vector 中元素的数量为 n。如果 n 小于当前 size(),则减小 std::vector 的大小;如果 n 大于当前 size(),则增加元素,并用默认构造函数初始化新元素。
std::vector<int> vec = {1, 2, 3};
vec.resize(5); // 现在 vec 包含 {1, 2, 3, 0, 0}

capacity()

  • capacity() 是 std::vector 的公有成员函数,返回当前 std::vector 分配的存储空间的容量,即可以在不重新分配内存的情况下存储的元素个数。
std::vector<int> vec = {1, 2, 3};
std::cout << "Capacity of vec: " << vec.capacity() << std::endl;

empty()

  • empty() 是 std::vector 的公有成员函数,用于检查 std::vector 是否为空,即其 size() 是否为 0。
std::vector<int> vec = {1, 2, 3};
if (vec.empty()) {
    std::cout << "Vector is empty" << std::endl;
}

reserve(size_type n)

  • reserve(n) 是 std::vector 的公有成员函数,请求 std::vector 预留至少能容纳 n 个元素的内存空间,但不改变 std::vector 的大小(即 size() 不会改变)。
std::vector<int> vec = {1, 2, 3};
vec.reserve(10); // 预留至少能容纳 10 个元素的内存空间

shrink_to_fit()

  • shrink_to_fit() 是 std::vector 的公有成员函数,请求 std::vector 收缩其容量以适合其当前大小。这个函数的调用并不保证 capacity() 会改变,但通常会导致它不大于 size() 返回的元素数量。
std::vector<int> vec = {1, 2, 3};
vec.shrink_to_fit(); // 可能会减少容量以适合当前大小

操作函数

push_back(const T& value)

  • push_back 是 std::vector 的公有成员函数,用于将元素 value 添加到 std::vector 的末尾。push_back 会在 std::vector 的末尾添加一个元素,并增加其大小。
std::vector<int> vec = {1, 2, 3};
vec.push_back(4); // 现在 vec 包含 {1, 2, 3, 4}

pop_back()

  • pop_back 是 std::vector 的公有成员函数,用于删除 std::vector 的末尾元素。它会减少 std::vector 的大小,但不会改变其容量。
std::vector<int> vec = {1, 2, 3};
vec.pop_back(); // 现在 vec 包含 {1, 2}

insert(iterator position, const T& value)

  • insert 是 std::vector 的公有成员函数,用于在指定位置 position 插入元素 value。插入操作会将现有元素和后续元素向后移动,以便在指定位置插入新元素。
std::vector<int> vec = {1, 2, 3};
vec.insert(vec.begin() + 1, 4); // 在第二个位置插入元素 4,现在 vec 包含 {1, 4, 2, 3}

erase(iterator position)

  • erase 是 std::vector 的公有成员函数,用于从指定位置 position 删除一个元素。删除操作会使该位置后续的元素向前移动,填补被删除的位置。
std::vector<int> vec = {1, 2, 3};
vec.erase(vec.begin() + 1); // 删除第二个位置的元素,现在 vec 包含 {1, 3}

swap(vector& other)

  • swap 是 std::vector 的公有成员函数,用于交换两个 std::vector 的内容。交换操作会交换两个 std::vector 的元素,并且它们的容量可能会因此而变化。
std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = {4, 5};
vec1.swap(vec2); // 现在 vec1 包含 {4, 5},vec2 包含 {1, 2, 3}

clear()

  • clear 是 std::vector 的公有成员函数,用于清空 std::vector 的内容,使其变为空 std::vector,但不影响其容量。
std::vector<int> vec = {1, 2, 3};
vec.clear(); // 现在 vec 是一个空的 std::vector

vector-bool

std::vector<bool> 是 C++ 标准库中的一种特化形式,用于保存布尔值的动态数组。它相比一般的 std::vector<T> 在内部实现上有所不同,主要为了优化空间使用。

特点和用法:

内部表示

std::vector 通常会使用位压缩(bit compression)来存储布尔值,而不是使用每个布尔值一个字节(8 bits)。这种压缩可以减少内存占用,但会影响访问元素的复杂性和性能。

访问元素

直接访问 std::vector 的元素可能不像普通的 std::vector 那样高效,因为元素可能不是直接可寻址的,而是通过位掩码来访问。

操作和接口

std::vector 支持大多数 std::vector 的操作,如动态增加大小、访问元素、迭代器等。但有些接口因为内部的位压缩表示可能会有所限制或行为不同。

注意事项

由于其特殊的实现方式,std::vector 与其他 std::vector 特化的行为可能会有所不同,例如迭代器的行为可能不同于标准的 std::vector。

示例用法:

#include <iostream>
#include <vector>

int main() {
    std::vector<bool> bits = {true, false, true, true};

    // 访问元素
    std::cout << "bits[0] = " << bits[0] << std::endl; // 输出 1,即 true

    // 添加元素
    bits.push_back(false);

    // 迭代输出
    for (auto bit : bits) {
        std::cout << bit << " ";
    }
    std::cout << std::endl;

    return 0;
}

总结
std::vector 是用于节省空间的特化 std::vector,适合大量布尔值的存储和操作。但需要注意其内部实现可能带来的访问和操作上的差异,特别是在需要频繁访问和修改元素时。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值