C++:STL - vector

简介: C++:STL - vector



C++的vector是一种可变长度的动态数组,被广泛用于C++编程中。它是标准模板库(STL)中的容器之一,提供了比原始数组更灵活和方便的操作。

vector可以存储任意类型的元素,包括基本类型(如整数和浮点数)和自定义类型(如类和结构体)。它的大小可以根据需要动态调整,而不需要手动管理内存。

vector支持随机访问,即可以通过下标直接访问容器中的元素。它还提供了一系列的成员函数和操作符,如插入、删除和查找等,使得对元素的操作变得更加方便和高效。

vector的内部实现使用了动态数组,当存储元素的个数超过当前容量时,会自动分配更大的内存空间,并将元素从旧的内存复制到新的内存中。这种动态分配和释放内存的特性使得vector能够有效地处理不可预知的元素个数。

要使用vector,首先需要包含头文件<vector>。然后可以用vector< T >声明一个vector对象,其中T表示要存储的元素类型。例如,可以使用vector< int >来声明一个存储整数的vector对象。

vector是C++中非常实用的容器,它提供了简洁、高效的操作,使得动态数组的使用变得更加方便。使用vector可以避免手动管理内存和处理数组大小的复杂逻辑。


构造函数

vector提供了多种构造函数来创建和初始化vector对象。

  1. 默认构造函数:
vector();
  1. 用于创建一个空的vector。
    示例:
vector<int> vec;  // 创建一个空的整数类型的vector
  1. 带有初始值的构造函数:
vector(size_type count, const T& value = T());
  1. 创建包含count个元素的vector,每个元素都初始化为value的值。
    示例:
vector<int> vec(5, 10);  // 创建一个包含5个元素,每个元素都为10的整数类型的vector
  1. 基于范围的构造函数:
template <class InputIterator>
vector(InputIterator first, InputIterator last);
  1. 创建一个包含[first, last)范围内元素的vector。
    示例:
int arr[] = {1, 2, 3, 4, 5};
vector<int> vec(arr, arr + 5);  // 创建一个包含数组中所有元素的整数类型的vector
  1. 拷贝构造函数:
vector(const vector& other);
  1. 创建一个与other相同元素的vector。
    示例:
vector<int> vec1(5, 10);  // 创建一个包含5个元素,每个元素都为10的整数类型的vector
vector<int> vec2(vec1);   // 创建一个与vec1相同元素的整数类型的vector

以上是vector的常用构造函数,可以根据具体需求选择合适的构造函数来创建vector对象。


修改操作

push_back

push_back()vector类的成员函数之一,用于在vector的尾部插入一个新的元素。

push_back()函数的语法如下:

void push_back (const value_type& val);

其中,value_type表示vector中存储的元素类型,val是要插入的新元素。

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> myVector;
    // 使用push_back()函数插入元素
    myVector.push_back(10);
    myVector.push_back(20);
    myVector.push_back(30);
    // 打印vector中的元素
    for(int i = 0; i < myVector.size(); i++) {
        std::cout << myVector[i] << " ";
    }
    std::cout << std::endl;
    return 0;
}

输出结果为:

10 20 30

首先,我们创建了一个空的vector对象myVector。然后,使用三次push_back()函数分别插入了整数值102030。最后,通过循环遍历vector,打印出了vector中的元素。

可以看到,push_back()函数将新元素添加到了vector的尾部。由于vector是动态大小的,因此可以随时在尾部插入新的元素,并且vector会自动调整大小以容纳新的元素。

需要注意的是,push_back()函数的参数是一个常量引用,这是为了防止在插入元素时进行不必要的拷贝操作,以提高性能。


pop_back

vectorpop_back()函数用于删除向量中的最后一个元素,并将容器的大小减1。不返回任何值。

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> vec;
    
    // 向向量中插入元素
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    
    std::cout << "元素:";
    for (int i : vec) {
        std::cout << " " << i;
    }
    std::cout << std::endl;
    
    // 使用pop_back()函数删除最后一个元素
    vec.pop_back();
    
    std::cout << "删除最后一个元素后:";
    for (int i : vec) {
        std::cout << " " << i;
    }
    std::cout << std::endl;
    
    return 0;
}

输出结果:

元素: 1 2 3
删除最后一个元素后: 1 2

在上面的代码中,我们首先创建了一个空的vector vec。然后使用push_back()函数向向量中插入三个元素(1,2,3)。接下来,我们使用pop_back()函数删除最后一个元素。最后,我们分别使用循环打印出原始的和删除最后一个元素后的vector

需要注意的是,如果vector是空的,调用pop_back()函数将引发未定义的行为。因此,在使用pop_back()函数之前,最好先检查vector是否为空。可以使用empty()函数来完成此操作。


erase

vectorerase函数用于删除指定位置的元素,其原型如下:

iterator erase (iterator position);
iterator erase (iterator first, iterator last);

第一种形式的erase函数用于删除指定位置的元素,它接受一个迭代器参数position,表示要删除的元素的位置。该函数返回一个指向被删除元素之后元素的迭代器。

第二种形式的erase函数用于删除指定范围内的元素,它接受两个迭代器参数firstlast,表示要删除的范围。该函数删除范围内的所有元素,并返回一个指向最后一个被删除元素之后元素的迭代器。

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // 删除指定位置的元素
    std::vector<int>::iterator it = v.begin() + 2;
    it = v.erase(it);
    // 输出: 1 2 4 5
    for (int i : v) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    
    // 删除指定范围内的元素
    std::vector<int>::iterator first = v.begin() + 1;
    std::vector<int>::iterator last = v.begin() + 3;
    v.erase(first, last);
    // 输出: 1 5
    for (int i : v) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

在上述代码中,我们首先创建了一个vector对象v,并初始化了5个元素。然后我们使用erase函数删除了指定位置的元素(第3个元素),并输出了剩余的元素。接着我们使用erase函数删除了指定范围内的元素(第2个和第3个元素),并再次输出了剩余的元素。

输出结果如下:

1 2 4 5
1 5

通过这个例子,我们可以看到使用erase函数可以有效地删除vector中的元素。


访问操作

empty

vectorempty函数可以用来检查向量是否为空。当向量为空时,返回true;否则,返回false

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers;
    if (numbers.empty()) {
        std::cout << "vector为空" << std::endl;
    } else {
        std::cout << "vector不为空" << std::endl;
    }
    numbers.push_back(10);
    if (numbers.empty()) {
        std::cout << "vector为空" << std::endl;
    } else {
        std::cout << "vector不为空" << std::endl;
    }
    
    return 0;
}

在这个例子中,开始时我们声明了一个numbers。然后,我们使用empty函数检查vector是否为空。由于开始时vector是空的,所以输出的结果是"vector为空"。

接着,我们使用push_back函数向vector中添加一个元素10。然后再次使用empty函数检查vector是否为空。由于vector中现在有一个元素,所以输出的结果是"vector不为空"。

通过这个例子,我们可以看到empty函数的用法和作用。它可以帮助我们判断一个vector是否为空,从而对vector进行进一步的操作。


operatror[]

vector可以提供高效的随机访问。

vectoroperator[]是一个重载运算符,用于访问vector中的元素。它的语法是vector_name[index],其中vector_namevector的名称,index是要访问的元素的索引。索引从0开始,表示vector中的第一个元素。

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    // 使用operator[]访问vector中的元素
    std::cout << numbers[0] << std::endl;  // 输出: 1
    std::cout << numbers[2] << std::endl;  // 输出: 3
    // 修改vector中的元素
    numbers[1] = 10;
    // 输出修改后的元素
    std::cout << numbers[1] << std::endl;  // 输出: 10
    return 0;
}

在上面的示例中,我们首先创建了一个vectornumbers并初始化了一些整数。然后,我们使用numbers[0]numbers[2]访问了vector中的元素,并将它们输出到控制台上。接着,我们将第二个元素修改为10,再次使用numbers[1]访问并输出修改后的元素。

需要注意的是,当使用operator[]访问vector时,如果索引超出了vector的范围,没有元素与该索引对应,将会导致未定义行为。因此,在使用operator[]之前,最好确保索引在合法范围内。


back

vectorback函数用于返回容器中最后一个元素的引用,即最后一个元素的值。如果容器为空,则未定义行为

案例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> vec;
    vec.push_back(10);
    vec.push_back(20);
    vec.push_back(30);
    int& lastElement = vec.back(); // 获取最后一个元素的引用
    std::cout << "最后一个元素的值为:" << lastElement << std::endl;
    return 0;
}

运行结果:

最后一个元素的值为:30

在上述案例中,我们创建了一个名为vecvector容器,并使用push_back函数依次将数值10、20和30添加到容器中。然后,通过调用back函数获取容器vec中最后一个元素的引用,并将其保存在lastElement变量中。最后,我们将所获得的最后一个元素的值打印出来。

需要注意的是,如果容器为空,那么调用back函数将会导致未定义行为。因此,在使用back函数之前,最好先使用empty函数检查容器是否为空。


front

front()vector容器的一个成员函数,用于获取容器中第一个元素的值。

示例:

#include <iostream>
#include <vector>
int main() {
    // 创建一个vector容器
    std::vector<int> myVector;
    // 向容器中添加元素
    myVector.push_back(10);
    myVector.push_back(20);
    myVector.push_back(30);
    // 使用front()函数获取容器中第一个元素的值
    int firstElement = myVector.front();
    // 输出第一个元素的值
    std::cout << "The first element is: " << firstElement << std::endl;
    return 0;
}

上面的代码首先创建了一个名为myVectorvector容器,并向其中添加了三个整数元素:10、20和30。然后使用front()获取了容器中第一个元素的值,并将其赋值给了变量firstElement。最后,通过cout输出了第一个元素的值。

运行上述代码,将会得到如下输出结果:

The first element is: 10

需要注意的是,如果vector容器为空,则调用front()函数将会引发未定义行为。因此,在使用front()之前,最好先检查vector是否为空,可以使用empty()进行判断。


容量操作

size

vectorsize函数用于获取vector中元素的数量。

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::cout << "Size of vector numbers: " << numbers.size() << std::endl;
    return 0;
}

在上述示例中,我们创建了一个名为numbersvector,并初始化它包含5个整数元素。然后,我们使用size函数获取vector numbers的大小,并将其打印出来。输出结果将是:

Size of vector numbers: 5

可以看到,numbers的大小为5,即它包含5个元素。


capacity

capacityvector中可以存储元素的总空间大小。

vector中的元素数量超过了它的容量时,vector会自动分配更多的内存空间,以容纳更多的元素。这个过程称为动态内存分配。动态内存分配是一种消耗时间和计算资源的操作,因此vector会在必要时一次性分配较大的内存空间,以减少动态内存分配的频率。

下面是一个案例,演示vector的capacity的变化:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> vec;
    std::cout << "Initial capacity: " << vec.capacity() << std::endl;
    std::cout << "Initial size: " << vec.size() << std::endl;
    // 向vector中添加元素
    for (int i = 0; i < 10; i++) {
        vec.push_back(i);
        std::cout << "Capacity after adding element " << i << ": " << vec.capacity() << std::endl;
        std::cout << "Size after adding element " << i << ": " << vec.size() << std::endl;
    }
    return 0;
}

输出结果为:

Initial capacity: 0
Initial size: 0
Capacity after adding element 0: 1
Size after adding element 0: 1
Capacity after adding element 1: 2
Size after adding element 1: 2
Capacity after adding element 2: 4
Size after adding element 2: 3
Capacity after adding element 3: 4
Size after adding element 3: 4
Capacity after adding element 4: 8
Size after adding element 4: 5
Capacity after adding element 5: 8
Size after adding element 5: 6
Capacity after adding element 6: 8
Size after adding element 6: 7
Capacity after adding element 7: 8
Size after adding element 7: 8
Capacity after adding element 8: 16
Size after adding element 8: 9
Capacity after adding element 9: 16
Size after adding element 9: 10

可以看到,vector在添加元素时,当元素数量超过当前容量时,会自动增加容量。初始时,vector的容量为0,添加第一个元素后,容量变为1;添加第二个元素后,容量变为2;添加第三个元素后,容量变为4;依次类推。当容量不足时,vector会分配更大的内存空间,容量会以指数级增长。注意,vector的容量并不等于元素的数量,它可以大于等于元素数量。


resize

vectorresize()函数是用于改变vector的大小的,它可以增加或缩小vector的元素数量。

resize()函数有两种形式:

  1. resize(n):将vector的大小改变为n。如果n小于当前的大小,则vector将被截断为前n个元素。如果n大于当前的大小,则vector的大小将增加,在末尾添加默认值的元素。
  2. resize(n, val):将vector的大小改变为n,并用val填充新添加的元素。如果n小于当前的大小,则vector将被截断为前n个元素。如果n大于当前的大小,则vector的大小将增加,新添加的元素用val填充。

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5};
    // 使用resize(n)来增加vector的大小
    nums.resize(7);
    std::cout << "After resize(7): ";
    for (int num : nums) {
        std::cout << num << " ";
    }
    // 输出: After resize(7): 1 2 3 4 5 0 0
    // 使用resize(n, val)来增加vector的大小,并用val填充
    nums.resize(10, 9);
    std::cout << "\nAfter resize(10, 9): ";
    for (int num : nums) {
        std::cout << num << " ";
    }
    // 输出: After resize(10, 9): 1 2 3 4 5 0 0 9 9 9
    // 使用resize(n)来缩小vector的大小
    nums.resize(3);
    std::cout << "\nAfter resize(3): ";
    for (int num : nums) {
        std::cout << num << " ";
    }
    // 输出: After resize(3): 1 2 3
    return 0;
}

在上面的例子中,我们先创建了一个包含5个整数的vector。然后使用resize()函数对其进行调整大小操作。首先使用resize(7)扩大vector的大小,新添加了两个默认值为0的元素。然后使用resize(10, 9)再次扩大vector的大小,新添加了三个值为9的元素。最后使用resize(3)缩小vector的大小,截断了后面的元素。在每次resize操作后,我们打印出vector的内容来验证结果。


reserve

由于vector的内存管理可能涉及动态分配和释放内存,这个过程可能会很耗时。为了优化性能,我们可以使用vectorreserve函数来预分配内存空间,以避免频繁的内存分配和释放操作。

reserve函数的函数原型如下:

void reserve (size_type n);

参数n指定了预分配的内存空间大小,以元素个数为单位。这意味着reserve函数将为vector预分配至少n个元素所需的内存空间。

示例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> vec;
    
    std::cout << "Before reserve: size = " << vec.size() << ", capacity = " << vec.capacity() << std::endl;
    
    vec.reserve(100); // 预分配至少100个元素的内存空间
    
    std::cout << "After reserve: size = " << vec.size() << ", capacity = " << vec.capacity() << std::endl;
    
    for (int i = 0; i < 50; i++) {
        vec.push_back(i);
    }
    
    std::cout << "After push_back: size = " << vec.size() << ", capacity = " << vec.capacity() << std::endl;
    
    return 0;
}

输出结果为:

Before reserve: size = 0, capacity = 0
After reserve: size = 0, capacity = 100
After push_back: size = 50, capacity = 100

从输出结果可以看出,我们在调用reserve函数之前,vectorsizecapacity都是0。调用reserve函数之后,虽然size仍然是0,但capacity变为了100,预分配了100个元素的内存空间。

当我们向vector中添加元素时,size会发生变化,而capacity则保持不变。可以看到,在向vector中添加了50个元素之后,size变为了50,而capacity仍然是100。

这说明,通过调用reserve函数预分配内存空间,可以有效避免频繁的内存分配和释放操作,从而提高程序的性能。

注意,reserve函数只会增加capacity,不会改变size的值


相关文章
|
16小时前
|
设计模式 算法 C++
【C++】STL之迭代器介绍、原理、失效
【C++】STL之迭代器介绍、原理、失效
13 2
|
16小时前
|
存储 C++ 容器
C++:STL - set & map
C++:STL - set & map
14 4
|
16小时前
|
编译器 C++ Windows
【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题)
不使用memcpy函数不就可以了,然后我们使用简单粗暴的赋值拷贝,这样就不会发生浅拷贝问题了!!!
16 1
|
16小时前
|
算法 安全 程序员
【C++】STL学习之旅——初识STL,认识string类
现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽
15 0
|
16小时前
|
存储 Serverless C++
【C++入门到精通】哈希 (STL) _ unordered_map _ unordered_set [ C++入门 ]
【C++入门到精通】哈希 (STL) _ unordered_map _ unordered_set [ C++入门 ]
10 1
|
16小时前
|
存储 设计模式 算法
【C++/STL】stack和queue(容器适配器、优先队列、双端队列)
【C++/STL】stack和queue(容器适配器、优先队列、双端队列)
14 1
|
16小时前
|
存储 编译器 C++
【C++/STL】list(常见接口、模拟实现、反向迭代器、)
【C++/STL】list(常见接口、模拟实现、反向迭代器、)
5 0
|
16小时前
|
算法 C++ 容器
【C++/STL】vector(常见接口、模拟实现、迭代器失效)
【C++/STL】vector(常见接口、模拟实现、迭代器失效)
11 0
|
16小时前
|
存储 算法 C++
详解C++中的STL(标准模板库)容器
【4月更文挑战第30天】C++ STL容器包括序列容器(如`vector`、`list`、`deque`、`forward_list`、`array`和`string`)、关联容器(如`set`、`multiset`、`map`和`multimap`)和容器适配器(如`stack`、`queue`和`priority_queue`)。它们为动态数组、链表、栈、队列、集合和映射等数据结构提供了高效实现。选择合适的容器类型可优化性能,满足不同编程需求。
|
16小时前
|
存储 算法 程序员
C++从入门到精通:2.2.1标准库与STL容器算法深度解析
C++从入门到精通:2.2.1标准库与STL容器算法深度解析