Day 23 C++ vector容器

vector容器

  • vector基本概念
      • 定义
      • vector容器的迭代器——支持随机访问的迭代器
      • vector与普通数组区别
          • 大小的灵活性
          • 内存管理
          • 访问效率
          • 功能和灵活性
      • 动态扩展
  • vector构造函数——创建vector容器
      • 函数原型
      • 示例
  • vector赋值操作
      • 函数原型
      • 示例
  • 对vector容器的容量和大小操作
      • 函数原型
      • 示例
  • 对vector容器进行插入、删除操作
      • 函数原型
      • 示例
  • 对vector中的数据的存取操作
      • 函数原型
      • 示例
      • 使用迭代器存取数据
  • 实现两个vector容器内元素进行互换
      • 函数原型
      • 示例
  • vector预留空间
      • 函数原型
      • 示例
      • 注意——如果数据量较大,可以一开始利用reserve预留空间

vector基本概念

定义

C++的vector容器是一个动态数组,提供了存储和操作元素的功能。它是标准模板库(STL)的一部分,在头文件中定义。

vector数据结构和数组非常相似,也称为单端数组动态数组)(也被称为向量

使用vector容器前,需要引入头文件:

#include 

vector容器的迭代器——支持随机访问的迭代器

vector与普通数组区别

大小的灵活性

数组是静态空间,而vector可以动态扩展普通数组在创建时需要指定固定的大小,而且不能动态改变大小。而vector容器是动态数组,可以根据需要自动调整大小。它会自动管理内存,并提供了函数来添加、删除、插入和操作元素。

内存管理

普通数组是在栈上分配内存,而vector容器使用堆内存。这意味着当数组很大时,使用vector可以避免栈溢出问题。另外,vector还提供了自动释放内存的机制,不需要手动释放内存。

访问效率

普通数组的元素访问效率更高,因为它们在内存中是连续存储的,可以直接通过索引来访问元素。而vector容器的元素存储在堆内存中,需要通过指针进行间接访问,可能会稍微降低一些效率。

功能和灵活性

vector容器提供了许多便捷的函数和操作符,使得处理和操作元素更加方便。它可以动态调整大小、插入和删除元素,提供了范围-based for循环和迭代器等功能,而普通数组需要手动编写相应的代码来实现这些功能。

综上所述,vector容器相比普通数组更加灵活和方便,尤其适用于需要动态改变大小或者进行复杂操作的场景。而普通数组则更适合在大小固定且访问效率要求较高的情况下使用。

动态扩展

并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间

vector容器在初始化时没有固定的大小限制,可以动态地添加或删除元素,以适应不同的需求。添加元素时,如果已经达到容器的容量上限,vector会自动分配更大的内存空间,并将原有的元素拷贝到新的内存中。这样就实现了动态扩展。


vector构造函数——创建vector容器

函数原型

  • vector v; //采用模板实现类实现,默认构造函数
  • vector(v.begin(), v.end()); //将v[begin(), end())区间中的元素拷贝给本身。
  • vector(n, elem); //构造函数将n个elem拷贝给本身。
  • vector(const vector &vec); //拷贝构造函数。

示例

#include 
#include 

int main() {
    // 使用默认构造函数创建空的vector容器
    std::vector emptyVector;
    
    // 使用迭代器范围方式创建vector容器
    int arr[] = {1, 2, 3, 4, 5};
    std::vector rangeVector(arr, arr + 5);
    
    // 使用重复元素方式创建vector容器
    std::vector repeatVector(5, 10);
    
    // 使用拷贝构造函数创建vector容器
    std::vector copyVector(rangeVector);

    // 打印各个vector容器的元素
    for (int element : emptyVector) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    
    for (int element : rangeVector) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    
    for (int element : repeatVector) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    
    for (int element : copyVector) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

在上述示例中,我们通过不同的方式创建了四个vector容器:使用默认构造函数创建了一个空的容器emptyVector,使用迭代器范围方式从数组中拷贝元素创建了容器rangeVector,使用重复元素方式创建了容器repeatVector,使用拷贝构造函数从另一个容器中拷贝元素创建了容器copyVector。然后,我们分别使用for循环打印四个vector容器的元素。

注意,在示例代码中,emptyVector是空的,因此不会输出任何内容。

运行该示例代码,输出为:

1 2 3 4 5
10 10 10 10 10
1 2 3 4 5

vector赋值操作

函数原型

  • vector& operator=(const vector &vec); //重载等号操作符
  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
  • assign(n, elem); //将n个elem拷贝赋值给本身。

注意
begend 都是迭代器

示例

#include 
#include 

int main() {
    std::vector vec1 = {1, 2, 3, 4, 5};
    std::vector vec2;
    
    // 使用重载等号操作符将vec1的元素赋值给vec2
    vec2 = vec1;
    
    // 使用assign函数将vec1的元素拷贝赋值给vec2
    vec2.assign(vec1.begin(), vec1.end());
    
    // 使用assign函数将重复的元素拷贝赋值给vec2
    vec2.assign(5, 10);
    
    // 打印vec1和vec2的元素
    for (int element : vec1) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    
    for (int element : vec2) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}



对vector容器的容量和大小操作

函数原型

  • empty(); //判断容器是否为空

  • capacity(); //容器的容量

  • size(); //返回容器中元素的个数

  • resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除

示例

#include 
#include 

int main() {
    std::vector vec = {1, 2, 3};
    
    // 使用empty()函数判断容器是否为空
    if (vec.empty()) {
        std::cout << "Vector is empty" << std::endl;
    } else {
        std::cout << "Vector is not empty" << std::endl;
    }
    
    // 使用capacity()函数获取容器的容量
    std::cout << "Capacity: " << vec.capacity() << std::endl;
    
    // 使用size()函数获取容器中元素的个数
    std::cout << "Size: " << vec.size() << std::endl;
    
    // 使用resize()函数修改容器的长度为5,默认使用0填充新位置
    vec.resize(5);
    
    // 输出修改后的容器元素
    for (int element : vec) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    
    // 使用resize()函数将容器的长度修改为3,并使用10填充新位置
    vec.resize(3, 10);
    
    // 输出修改后的容器元素
    for (int element : vec) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

在上述示例中,我们创建了一个初始容器vec,包含元素1、2和3。首先,使用empty()函数判断容器是否为空,如果为空则输出相应的提示信息。然后,使用capacity()函数获取容器的容量,并使用size()函数获取容器中元素的个数。接下来,使用resize()函数将容器的长度修改为5,默认使用0填充新位置。打印修改后的容器元素。接着,使用resize()函数将容器的长度修改为3,并使用10填充新位置。再次打印修改后的容器元素。

输出结果

Vector is not empty
Capacity: 3
Size: 3
1 2 3 0 0
1 2 3


对vector容器进行插入、删除操作

函数原型

  • push_back(ele); //尾部插入元素ele
  • pop_back(); //删除最后一个元素
  • insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele
  • insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele
  • erase(const_iterator pos); //删除迭代器指向的元素
  • erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
  • clear(); //删除容器中所有元素

示例

#include 
#include 

int main() {
    std::vector vec = {1, 2, 3};

    // 尾部插入元素ele
    vec.push_back(4);
    
    // 删除最后一个元素
    vec.pop_back();
    
    // 迭代器指向位置pos插入元素ele
    auto it = vec.begin() + 1;
    vec.insert(it, 10);
    
    // 迭代器指向位置pos插入count个元素ele
    vec.insert(it, 3, 20);
    
    // 删除迭代器指向的元素
    vec.erase(vec.begin() + 2);
    
    // 删除迭代器从start到end之间的元素
    vec.erase(vec.begin(), vec.begin() + 2);
    
    // 删除容器中所有元素
    vec.clear();
    
    // 输出修改后的容器元素
    for (int element : vec) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}


对vector中的数据的存取操作

函数原型

  • at(int idx); //返回索引idx所指的数据
  • operator[]; //返回索引idx所指的数据
  • front(); //返回容器中第一个数据元素
  • back(); //返回容器中最后一个数据元素

示例

#include 
#include 

int main() {
    std::vector vec = {1, 2, 3, 4, 5};

    // 使用 at() 函数返回索引 idx 所指的数据
    int value1 = vec.at(2);
    std::cout << "Value at index 2: " << value1 << std::endl;

    // 使用 operator[] 返回索引 idx 所指的数据
    int value2 = vec[3];
    std::cout << "Value at index 3: " << value2 << std::endl;

    // 使用 front() 函数返回容器中第一个数据元素
    int first = vec.front();
    std::cout << "First element: " << first << std::endl;

    // 使用 back() 函数返回容器中最后一个数据元素
    int last = vec.back();
    std::cout << "Last element: " << last << std::endl;

    return 0;
}

在上述示例中,我们创建了一个初始容器 vec,包含元素 1、2、3、4 和 5。然后,我们使用 at() 函数和索引 2 来访问容器中的元素。同样地,我们使用 operator[] 和索引 3 来访问容器中的元素。接下来,我们使用 front() 函数来访问容器中的第一个元素,并使用 back() 函数来访问容器中的最后一个元素。

输出结果

Value at index 2: 3
Value at index 3: 4
First element: 1
Last element: 5

使用迭代器存取数据

#include 
#include 

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用迭代器访问容器中的数据
    std::vector<int>::iterator it;
    
    // 使用迭代器遍历容器并输出数据
    std::cout << "Elements in the vector: ";
    for (it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

在上述示例中,我们创建了一个初始容器 vec,包含元素 1、2、3、4 和 5。
然后,我们声明了一个迭代器 it,并将其初始化为容器的起始位置(begin())
接下来,我们使用迭代器 it 遍历容器,并通过解引用操作符 *访问迭代器指向的元素。
在循环中,迭代器 it逐个移动到下一个元素,直到达到容器的末尾位置(end())为止
在循环过程中,我们输出迭代器指向的元素值。最后,我们输出一个换行符


实现两个vector容器内元素进行互换

函数原型

swap(vec); // 将vec与本身的元素互换

示例

#include 
#include 

int main() {
    std::vector vec = {1, 2, 3, 4, 5};

    std::cout << "Before swap:" << std::endl;
    for (const auto& value : vec) {
        std::cout << value << " ";
    }
    std::cout << std::endl;

    swap(vec); // 使用 std::swap 交换 vec 与本身的元素

    std::cout << "After swap:" << std::endl;
    for (const auto& value : vec) {
        std::cout << value << " ";
    }
    std::cout << std::endl;

    return 0;
}

在上述示例中,我们创建了一个初始容器 vec,包含元素 1、2、3、4 和 5。

然后,我们输出容器交换前的元素值。

接下来,我们调用 swap(vec),使用 std::swap 函数交换容器 vec 与其本身的元素,实现元素的重新排列。

最后,我们输出容器交换后的元素值

输出结果

Before swap:
1 2 3 4 5 
After swap:
5 4 3 2 1 

vector预留空间

可以减少vector在动态扩展容量时的扩展次数

函数原型

reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。
在调用 reserve() 函数时,需要提供一个整数值作为参数,表示预分配的最小容量。这个容量是指可以容纳的元素数量,并不是占用的字节大小

示例

#include 
#include 

int main() {
    std::vector vec;

    std::cout << "Capacity before reserve: " << vec.capacity() << std::endl;
    
    vec.reserve(10); // 预留至少能容纳10个元素的空间

    std::cout << "Capacity after reserve: " << vec.capacity() << std::endl;

    return 0;
}

我们创建了一个空的 std::vector 容器 vec。

然后,我们输出容器调用 reserve() 函数之前的容量。

接下来,我们调用 vec.reserve(10),预留至少能容纳 10 个元素的空间。

最后,我们输出容器调用 reserve() 函数之后的容量。

输出

Capacity before reserve: 0
Capacity after reserve: 10

注意——如果数据量较大,可以一开始利用reserve预留空间


如果事先知道容器将要存储大量的元素,那么通过使用 reserve() 函数来预留空间是一个很好的做法。这样可以避免在插入元素时多次重新分配内存,从而提高性能。

预留足够的空间以容纳数据可以减少频繁的重新分配和复制操作,从而提高程序的效率。特别是对于大型数据集或需要频繁插入或添加元素的情况,这一点尤为重要。

你可能感兴趣的:(C,++,c++,开发语言)