zoukankan      html  css  js  c++  java
  • 【校招面试 之 C/C++】第20题 C++ STL(二)之Vector

    1、vector的动态增长

      当添加元素时,如果vector空间大小不足,则会以原大小的两倍另外配置一块较大的新空间,然后将原空间内容拷贝过来在新空间的内容末尾添加元素,并释放原空间。vector的空间动态增加大小,并不是在原空间之后的相邻地址增加新空间,因为vector的空间是线性连续分配的,不能保证原空间之后有可供配置的空间。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就会失效

    vector的size(),capacity(),reserve(),resize()函数:

    vector对象的内存布局如下图所示:

    start迭代器指向已用空间的首元素,finish指向已用空间的尾元素的下一个位置,end_of_storage指向可用空间的末尾。
         size()函数返回的是已用空间大小,capacity()返回的是总空间大小,capacity()-size()则是剩余的可用空间大小。当size()和capacity()相等,说明vector目前的空间已被用完,如果再添加新元素,则会引起vector空间的动态增长。
         由于动态增长会引起重新分配内存空间、拷贝原空间、释放原空间,这些过程会降低程序效率。因此,可以使用reserve(n)预先分配一块较大的指定大小的内存空间,这样当指定大小的内存空间未使用完时,是不会重新分配内存空间的,这样便提升了效率。只有当n>capacity()时,调用reserve(n)才会改变vector容量。
        resize()成员函数只改变元素的数目,不改变vector的容量。
     
    程序说明:
        分配了两个容器a,b。其中每次往a中添加1个元素,共添加10次。使用reserve()预先为b分配一块10个元素大小的空间,之后才每次往b中添加1个元素,共添加10次。当b空间满后,再往其中添加1个元素。之后使用reserve()为b分配一块15(比原空间小)个元素大小的空间。再使用resize()将b的元素个数改变为5个。
        观察上述过程中size()和capacity()大小的变化。
    #include <iostream>
    #include <vector>
    using namespace std;
    int main()
    {
        vector<int> a;
        cout << "a.size(): " << a.size() << "       a.capacity(): " << a.capacity() << endl;
        for (int i = 0; i < 10; i++)
        {
            a.push_back(i);
            cout << "a.size(): " << a.size() << "   a.capacity(): " << a.capacity() << endl;
        }
        cout << endl;
        vector<int> b;
        b.reserve(10);
        for (int i = 0; i < 10; i++)
        {
            b.push_back(i);
            cout << "b.size(): " << b.size() << "   b.capacity(): " << b.capacity() << endl;
        }
        b.push_back(11);
        cout << "b.size(): " << b.size() << "       b.capacity(): " << b.capacity() << endl;
        cout << endl;
        b.reserve(15);
        cout << "after b.reserve(15):" << endl;
        cout << "b.size(): " << b.size() << "       b.capacity(): " << b.capacity() << endl;
        b.resize(5);
        cout << "after b.resize(5):" << endl;
        cout << "b.size(): " << b.size() << "       b.capacity(): " << b.capacity() << endl;
        return 0;
    }
    输出:
    a.size(): 0 a.capacity(): 0 a.size(): 1 a.capacity(): 1 a.size(): 2 a.capacity(): 2 a.size(): 3 a.capacity(): 4 a.size(): 4 a.capacity(): 4 a.size(): 5 a.capacity(): 8 a.size(): 6 a.capacity(): 8 a.size(): 7 a.capacity(): 8 a.size(): 8 a.capacity(): 8 a.size(): 9 a.capacity(): 16 a.size(): 10 a.capacity(): 16 b.size(): 1 b.capacity(): 10 b.size(): 2 b.capacity(): 10 b.size(): 3 b.capacity(): 10 b.size(): 4 b.capacity(): 10 b.size(): 5 b.capacity(): 10 b.size(): 6 b.capacity(): 10 b.size(): 7 b.capacity(): 10 b.size(): 8 b.capacity(): 10 b.size(): 9 b.capacity(): 10 b.size(): 10 b.capacity(): 10 b.size(): 11 b.capacity(): 20 after b.reserve(15): b.size(): 11 b.capacity(): 20 after b.resize(5): b.size(): 5 b.capacity(): 20
    现象:a重新分配空间共5次,每次都为之前空间的2倍。b在未超出reserve()预分配的空间时没有重新分配。
    结论:
        1. 空的vector对象,size()和capacity()都为0
        2. 当空间大小不足时,新分配的空间大小为原空间大小的2倍
        3. 使用reserve()预先分配一块内存后,在空间未满的情况下,不会引起重新分配,从而提升了效率
        4. 当reserve()分配的空间比原空间小时,是不会引起重新分配的
        5. resize()函数只改变容器的元素数目,未改变容器大小(capacity())

    2、vector的用法

    (1)头文件

    #include<vector>
    

    (2)声明以及初始化

    vector<int> vec;        //声明一个int型向量
    vector<int> vec(5);     //声明一个初始大小为5的int向量
    vector<int> vec(10, 1); //声明一个初始大小为10且值都是1的向量
    vector<int> vec(tmp);   //声明并用tmp向量初始化vec向量
    vector<int> tmp(vec.begin(), vec.begin() + 3);  //用向量vec的第0个到第2个值初始化tmp
    int arr[5] = {1, 2, 3, 4, 5};   
    vector<int> vec(arr, arr + 5);      //将arr数组的元素用于初始化vec向量
    //说明:当然不包括arr[4]元素,末尾指针都是指结束元素的下一个元素,
    //这个主要是为了和vec.end()指针统一。
    vector<int> vec(&arr[1], &arr[4]); //将arr[1]~arr[4]范围内的元素作为vec的初始值
    

    (3)基本操作

    1️⃣容量

    • 向量大小: vec.size();
    • 向量最大容量: vec.max_size();
    • 更改向量大小: vec.resize();
    • 向量真实大小: vec.capacity();
    • 向量判空: vec.empty();
    • 减少向量大小到满足元素所占存储空间的大小: vec.shrink_to_fit(); //shrink_to_fit

    2️⃣修改

    • 多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值
    • 末尾添加元素: vec.push_back();
    • 末尾删除元素: vec.pop_back();
    • 任意位置插入元素: vec.insert();
    • 任意位置删除元素: vec.erase();
    • 交换两个向量的元素: vec.swap();
    • 清空向量元素: vec.clear();

    3️⃣迭代器

    • 开始指针:vec.begin();
    • 末尾指针:vec.end(); //指向最后一个元素的下一个位置
    • 指向常量的开始指针: vec.cbegin(); //意思就是不能通过这个指针来修改所指的内容,但还是可以通过其他方式修改的,而且指针也是可以移动的。
    • 指向常量的末尾指针: vec.cend();

    4️⃣元素的访问

    • 下标访问: vec[1]; //并不会检查是否越界
      • at方法访问: vec.at(1);   //以上两者的区别就是at会检查是否越界,是则抛出out of range异常
    • 访问第一个元素: vec.front();
    • 访问最后一个元素: vec.back();
    • 返回一个指针: int* p = vec.data(); //可行的原因在于vector在内存中就是一个连续存储的数组,所以可以返回一个指针指向这个数组。这是是C++11的特性

    5️⃣算法

    遍历

    vector<int>::iterator it;
    for (it = vec.begin(); it != vec.end(); it++)
        cout << *it << endl;
    //或者
    for (size_t i = 0; i < vec.size(); i++) {
        cout << vec.at(i) << endl;
    }
    
  • 相关阅读:
    js中this指向的三种情况
    js 对象克隆方法总结(不改变原对象)
    JS 数组克隆方法总结(不可更改原数组)
    第七章、函数的基础之函数体系01
    第六篇、文件处理之文件修改的两种方式
    第六篇、文件处理之文件的高级应用
    第六篇.文件处理之python2和3字符编码的区别
    第六篇、文件处理之字符编码
    第五篇python进阶之深浅拷贝
    jquery的insertBefore(),insertAfter(),after(),before()
  • 原文地址:https://www.cnblogs.com/xuelisheng/p/9347544.html
Copyright © 2011-2022 走看看