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的值


相关文章
|
7天前
|
编译器 C语言 C++
【c++丨STL】list模拟实现(附源码)
本文介绍了如何模拟实现C++中的`list`容器。`list`底层采用双向带头循环链表结构,相较于`vector`和`string`更为复杂。文章首先回顾了`list`的基本结构和常用接口,然后详细讲解了节点、迭代器及容器的实现过程。 最终,通过这些步骤,我们成功模拟实现了`list`容器的功能。文章最后提供了完整的代码实现,并简要总结了实现过程中的关键点。 如果你对双向链表或`list`的底层实现感兴趣,建议先掌握相关基础知识后再阅读本文,以便更好地理解内容。
15 1
|
20天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
34 7
|
2月前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
66 4
|
2月前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
81 5
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
63 2
|
19天前
|
存储 对象存储 C++
C++ 中 std::array<int, array_size> 与 std::vector<int> 的深入对比
本文深入对比了 C++ 标准库中的 `std::array` 和 `std::vector`,从内存管理、性能、功能特性、使用场景等方面详细分析了两者的差异。`std::array` 适合固定大小的数据和高性能需求,而 `std::vector` 则提供了动态调整大小的灵活性,适用于数据量不确定或需要频繁操作的场景。选择合适的容器可以提高代码的效率和可靠性。
41 0
|
2月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
61 0
|
23天前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
31 0
|
3月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
89 5
|
3月前
|
存储 C++ 索引
【C++打怪之路Lv9】-- vector
【C++打怪之路Lv9】-- vector
27 1