C++里的vector详细讲解

在C++的标准模板库(STL)中,vector是一个非常有用的动态数组容器。它允许我们存储可变大小的同类型元素序列,并且能够动态地增长和缩小。由于其灵活性和易用性,vector在C++编程中得到了广泛的应用。

一、vector的基本操作

1. 包含头文件

要使用vector,首先需要包含相应的头文件:

#include <vector>
2. 创建vector对象

创建一个空的int类型的vector

std::vector<int> v;

创建一个包含10个整数的vector,并初始化为0:

std::vector<int> v(10, 0);
3. 添加元素

使用push_back()函数向vector的末尾添加一个元素:

v.push_back(1);
v.push_back(2);
4. 访问元素

使用下标运算符[]来访问vector中的元素:

int first_element = v[0];  // 访问第一个元素
v[1] = 3;  // 修改第二个元素的值为3
5. 删除元素

使用erase()函数删除指定位置的元素:

v.erase(v.begin() + 1);  // 删除第二个元素
6. 遍历元素

使用迭代器或范围for循环遍历vector中的元素:

// 使用迭代器遍历
for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
    std::cout << *it << " ";
}
std::cout << std::endl;

// 使用范围for循环遍历
for (const auto& element : v) {
    std::cout << element << " ";
}
std::cout << std::endl;
7. 获取vector的大小和容量

使用size()函数获取vector中元素的数量,使用capacity()函数获取vector当前分配的内存空间能够容纳的元素数量:

std::cout << "Size: " << v.size() << std::endl;
std::cout << "Capacity: " << v.capacity() << std::endl;

二、vector的特点和优势

  1. 动态扩展:当向vector中添加元素时,如果当前分配的内存空间不足以容纳新元素,vector会自动重新分配更大的内存空间,并复制或移动原有元素到新的内存空间。这个过程对用户是透明的,无需手动管理内存。
  2. 连续存储vector中的元素在内存中是连续存储的,这使得访问和操作元素非常高效。同时,连续存储也方便了元素的遍历和查找。
  3. 类型安全vector是模板类,可以存储任意类型的元素(包括基本数据类型、自定义类型等),并且保证了类型安全。在编译时会检查元素的类型,避免了运行时类型错误的风险。
  4. 易于使用vector提供了丰富的成员函数和操作符重载,使得对容器的操作更加直观和方便。例如,可以使用==运算符比较两个vector是否相等,使用+=运算符向vector中添加元素等。

三、示例代码

下面是一个简单的示例代码,演示了如何使用vector进行基本的操作:

#include <iostream>
#include <vector>

int main() {
    // 创建一个空的int类型的vector
    std::vector<int> v;
    
    // 向vector中添加元素
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    
    // 访问和修改元素
    std::cout << "First element: " << v[0] << std::endl;  // 输出:First element: 1
    v[1] = 4;  // 修改第二个元素的值为4
    
    // 遍历元素并输出
    std::cout << "Elements in vector: ";
    for (const auto& element : v) {
        std::cout << element << " ";
    }
    std::cout << std::endl;  // 输出:Elements in vector: 1 4 3 
    
    // 删除第二个元素(现在的值为4的元素)
    v.erase(v.begin() + 1);
    
    // 再次遍历元素并输出
    std::cout << "Elements after deletion: ";
    for (const auto& element : v) {
        std::cout << element << " ";
    }
    std::cout << std::endl;  // 输出:Elements after deletion: 1 3 
    
    return 0;
}

四、vector的性能考虑

虽然vector提供了很多便利,但在某些情况下,其性能可能并不是最优的。这主要源于vector在动态扩展时可能涉及大量的内存分配和数据复制。以下是一些使用vector时需要考虑的性能因素:

  1. 内存分配和复制:当vector需要增长时,它通常会分配一个更大的内存块,并将旧元素复制到新位置。这个过程可能很耗时,特别是对于大型vector。因此,如果你知道将要存储的元素数量,最好提前使用reserve()函数预留足够的空间。

  2. 连续内存访问:由于vector的元素在内存中是连续存储的,因此访问它们的性能通常很好。然而,插入或删除元素(特别是在vector的中间)可能会导致大量元素的移动,从而影响性能。在这种情况下,使用其他数据结构(如listdeque)可能更为合适。

  3. 缓存友好性:由于vector的元素是连续存储的,因此它们更容易被CPU缓存,从而提高访问速度。但是,当vector变得非常大时,它可能无法完全适应缓存,导致性能下降。

五、高级用法和注意事项

1. 使用emplace_back()避免不必要的复制或移动

当你想在vector的末尾添加一个元素时,如果元素类型是一个复杂的对象,使用emplace_back()而不是push_back()可以避免不必要的复制或移动操作。emplace_back()允许你在容器内直接构造元素,而无需先创建一个临时对象再将其复制或移动到容器中。

std::vector<std::string> strVec;
strVec.emplace_back("Hello");  // 直接在vector中构造std::string对象
2. 使用reserve()优化性能

如果你知道将要添加到vector中的元素数量,可以使用reserve()函数提前分配足够的内存空间。这样可以避免多次重新分配内存和数据复制,从而提高性能。

std::vector<int> intVec;
intVec.reserve(1000);  // 预留空间以存储1000个整数
for (int i = 0; i < 1000; ++i) {
    intVec.push_back(i);
}
3. 使用shrink_to_fit()释放未使用的内存

在删除大量元素后,vector可能不会立即释放未使用的内存。你可以调用shrink_to_fit()来请求容器减小其容量以匹配当前的大小。但请注意,这只是一个请求,标准库并不保证一定会释放内存。

std::vector<int> intVec(1000);
// ... 使用intVec ...
intVec.clear();  // 清除所有元素
intVec.shrink_to_fit();  // 请求释放未使用的内存
4. 避免在循环中多次调用size()

在循环中多次调用size()函数可能会导致不必要的性能开销,特别是当循环体很大且迭代次数很多时。最好将size()的结果存储在一个变量中,并在循环中使用该变量。

std::vector<int> intVec = {1, 2, 3, 4, 5};
size_t size = intVec.size();
for (size_t i = 0; i < size; ++i) {
    // ... 使用intVec[i] ...
}

六、总结

vector是C++ STL中非常强大且易于使用的动态数组容器。它提供了灵活的内存管理、高效的元素访问和丰富的操作函数。然而,在使用vector时,我们也应该注意其性能特点和最佳实践,以确保代码的高效运行。通过合理使用vector的成员函数和注意避免一些常见陷阱,我们可以充分利用这个容器的优势来编写高效且可靠的C++代码。

  • 25
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
约瑟夫环是一种经典的问题,其描述如下: 有n个人围成一圈,从第一个人开始报数,报到m的人出圈,剩下的人重新排成一圈,继续从第一个人开始报数,报到m的人再次出圈,如此循环,直到所有人都出圈为止。求出出圈的顺序。 这个问题可以用vector来实现。具体思路如下: 首先,我们需要用vector来表示所有人的编号,可以用一个循环将编号从1到n依次添加到vector中。 接着,我们需要用一个循环来模拟报数的过程。在每一轮中,从当前位置开始,依次数m个人,将第m个人从vector中删除,并记录其编号。 当vector中只剩下一个人时,停止循环,输出所有出圈人的编号即可。 下面是完整的代码实现: ```c++ #include <iostream> #include <vector> using namespace std; int main() { int n, m; cin >> n >> m; vector<int> nums; for(int i = 1; i <= n; i++) { nums.push_back(i); } vector<int> out; int idx = 0; while(nums.size() > 1) { idx = (idx + m - 1) % nums.size(); out.push_back(nums[idx]); nums.erase(nums.begin() + idx); } out.push_back(nums[0]); for(int i = 0; i < out.size(); i++) { cout << out[i] << " "; } cout << endl; return 0; } ``` 在这个代码中,我们首先使用cin读入n和m,然后创建一个vector nums,并将1到n的编号依次添加到vector中。 接着使用一个while循环模拟报数的过程。在每一轮中,我们使用变量idx记录当前位置,然后依次数m个人,将第m个人从vector中删除,并将其编号添加到另一个vector out中。 当vector nums中只剩下一个人时,停止循环,将最后一个人的编号添加到out中。 最后,我们输出所有出圈人的编号即可。 这个代码使用了vector的erase函数来删除vector中的元素,并使用了取模运算来实现循环计数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值