STL—vector

文章详细介绍了C++标准库中的vector容器,包括其初始化、内置函数、增删查改操作以及底层实现。特别讨论了vector的迭代器使用,以及在插入和删除操作中可能导致的迭代器失效问题及其解决方法。同时,文章提到了vector的优缺点和适用场景,并给出了模拟实现vector的类模板。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vector介绍

在C++标准库中,vector是一个常用的序列式容器(线性结构),它就好比c语言中的数组,但是vector有一些数组没有的功能,是一个封装好了的类。

vector的迭代器是一个原生态的指针

想要使用vector需要先引入头文件:

#include<vector>

要使用vector的一些泛型算法需要引入头文件:

#include<algorithm>

vector底层实现

vector底层数据结构是一个动态开辟的一维数组

其内部含有三个指针(start,finish,end_of_storage)

vector的使用

初始化vector

vector<int> a;

初始化一个装有int类数据的容器,size为0

vector<int> a(10);

初始化一个装有int类数据的容器,size为10,每个数据的默认值为0

vector<int> a(10,-1);

初始化一个装有int类数据的容器,size为10,每个数据初始化为-1

vector<int> b;

vector<int> a(b);

先初始化一个装有int类数据容器b

再使用容器b给装有int类数据容器a初始化

vector<int> b(5,2);

vector<int>a(b.begin(),b.begin()+3);

先初始化一个装有int类数据容器b,size为5,每个数据初始化为2

再用容器b的0-2下标数据(共3个)给装有int类数据容器a初始化,size为3

vector的一些内置函数

vector<int> a;
a.front();  //返回容器第一个元素的值
a.back();   //返回容器最后一个元素的值
a.begin();  //返回指向容器第一个元素的迭代器
a.end();  //返回指向容器最后一个元素下一个位置的迭代器
a[i];  //返回容器第i下标的值
a.clear();  //清空容器的值(size=0, capacity不变)
a.empty();  //判空,如果容器为空则返回true,不为空返回false

vector迭代器iterator的使用

vector<int> a(10,2);

vector<int>::iterator it = a.begin();

初始化一个装有整形数据的容器a,size=10,每个数据初始化为2

初始化指向int类数据的迭代器it,并指向a的第一个元素

it.begin()

返回所指向容器的第一个元素位置的迭代器

it.end()

返回指向最后一个元素下一个位置的迭代器

it.rbegin()

返回指向最后一个元素位置的迭代器

it.rend()

返回指向第一个元素前一个位置的迭代器

vector增删查改

查:

iteratror find( iteratror begin,iteratror end,int val ):在begin到end范围查找val

begin:查找范围起始位置的迭代器

end:查找范围终止位置的迭代器(查找的数包括这一个数)

val:要查找的数值

返回值:如果找到,返回指向此数的迭代器

如果没有找到,返回此容器的end()【指向最后一个元素的下一个位置的迭代器】

查找范围内存在的数

查找范围内不存在的数

增:

尾插:push_back( int a ):尾部插入元素a

指定位置之前插入:insert( 指向此位置的迭代器,int a ):

返回值:新插入位置的迭代器

typedef vector<int> _vector;
typedef vector<int>::iterator _it;

_vector _insert()
{
    _vector a;
    for (int i = 0; i < 5; i++)
    {
        a.push_back(i);
    }
    return a;
}

void print(_vector a,_it it)
{
    for (it = a.begin(); it != a.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
int main()
{
    _vector a;
    a = _insert();
    _it it = a.begin();
    print(a,it);
    it = find(a.begin(),a.end(),3);
    a.insert(it, 10);   //在容器内3的前面插入数据10
    print(a, it);
    return 0;
}

运行结果:

insert插入原理:

增容
改变size和capacity大小的vector内置函数

void resize( int newsize,int value ):重新设置容器的size

newsize:新设置的大小(小于原本的size则删除原本多出来的数据,大于原本的size则)

value:如果newsize>原本的size,则将多出来的空间赋值为value,如果不写默认是0

void reserve(int newstorage):重新设置容器的容量大小

newstorage:新的容量大小(如果小于原本大小就不进行任何操作)

vs的增容机制

总结:vs中vector增容按照1.5倍增容,Linux中vector增容按照2倍增容

增容的底层原理

删:

void pop_back():尾删

iterator arease( const_iterator first,const_iterator end ):删除范围内的元素(在内部erase会让迭代器++一次)

first:删除起始位置的迭代器

end:删除终止位置的迭代器

注意:如果只传一个迭代器,则只此位置的元素

返回值:删除后下一个元素的迭代器

错误演示:

在循环中使用erase的正确写法

erase删除原理

改:

通过[ ]运算符来进行修改,例如:

vector迭代器失效问题

迭代器的作用是让算法不用关心底层的数据 ,其底层实际就是一个指针。因此迭代器失效就是迭代器底层的指针指向的空间被销毁了,去使用一块已经被释放的空间,结果就是程序崩溃

在vector中,当我们在循环中使用push_back和erase时容易发生迭代器失效问题(即底层指针指向被释放的空间还依然去使用这个指针)

我们分别举两个例子来带大家了解迭代器失效问题。

erase删除导致的迭代器失效

我们在循环中去删除容器中的一个值

我们先给出错误代码

#include<iostream>
#include<vector>
using namespace std;

typedef vector<int> _vector;
typedef vector<int>::iterator _it;

int main()
{
    _vector a;
    for(int i =0;i<10;i++)
    {
        a.push_back(i);
    }
    _it it = a.begin();
    for (it; it != a.end();)
    {
        if (*it == 4)    //删除容器中的4
        {
            a.erase(it);  //没有去接收erase的返回值
        }
        else
        {
            it++;
        }
    }
    return 0;
}

在for循环中,当我们调用erase去删除2时,删除完成后没有用迭代器去接收erase的返回值(2的下一个元素的迭代器),此时迭代器不知道指向的哪里,此时若对迭代器进行操作会导致程序崩溃,也就是迭代器失效

如何避免erase导致的迭代器失效:

a.erase(it) 改为 it = a.erase(it)

insert插入导致的迭代器失效

我们在循环中去向容器中的一个元素前新插入一个值

我们先给出错误代码:

#include<iostream>
#include<vector>
using namespace std;

typedef vector<int> _vector;
typedef vector<int>::iterator _it;

int main()
{
    _vector a;
    for (int i = 0; i < 10; i++)
    {
        a.push_back(i);
    }
    _it it = a.begin();

    for (it; it != a.end();)
    {
        if (*it == 4)  //在元素4前新插入一个数15
        {
            a.insert(it, 15);
        }
        else
        {
            it++;
        }
    }
    return 0;
}

在for循环中,当我们调用insert在4前新插入元素时,插入完成后没有用迭代器去接收insert的返回值(新插入元素的下一个元素的迭代器),此时迭代器不知道指向的哪里,此时若对迭代器进行操作会导致程序崩溃,也就是迭代器失效

如何避免insert导致的迭代器失效:

a.insert(it,15) 改为 it = a.insert(it,15)

vector的优缺点

优点:尾部操作时间复杂度为O(1),支持随机访问[]
缺点:头部操作效率低,插入删除效率低,扩容会带来一定的空间浪费

vector的使用场景

当我们关心数据的随机访问,而不在意数据的插入删除效率时,我们使用vector

模拟实现vector

私有成员:

_iterator _start;
_iterator _finish;
_iterator _end_of_storage;

成员函数:

My_vector();
My_vector(int n,const T& val);
My_vector(otheriterator start,otheriterator finish);
My_vector(const My_vector<T>& v);
My_vector<T>& operator=( My_vector<T> v );

迭代器相关:

begin();
end();
rbegin();
rend();

容量大小相关:

size();
capacity();
resize( int newsize,const T& val = T() );
reserve( int newstorage );

元素访问:

T& front();
T& back();
T& operator[]( const int index );

元素修改:

push_back( const T& val );
pop_back();
insert( _iterator pos,const T& val );
erase( _iterator pos );

整体函数实现:

#include<iostream>
#include<stdlib.h>
#include<assert.h>
using namespace std;

template<class T>
class My_vector
{
public:
    //vector的迭代器是原生态的指针
    typedef T* _iterator;
    typedef const T* _const_iterator;
private:
    _iterator _start;
    _iterator _finish;
    _iterator _end_of_storage;
public:
/*-------------------------------------类的默认成员函数--------------------------------------------*/
    //缺省构造
    My_vector() :_start(nullptr), _finish(nullptr), _end_of_storage(nullptr) {}
    //构造
    My_vector(int n, const T& val = T()) :_start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
    {
        _start = new T[n];
        for (int i = 0; i < n; i++)
        {
            _start[i] = val;
        }
        _finish = _start + n;
        _end_of_storage = _finish;
    }
    
    //部分拷贝构造
    template<class otheriterator>
    My_vector(otheriterator start, otheriterator finish)
    {
        int size = 0;
        otheriterator it = start;
        while (it != finish)
        {
            ++it;
            ++size;
        }

        _start = new T[size];
        int i = 0;
        while(i < size)
        {
            _start[i] = *start;
            ++start;
            ++i;
        }
        _finish = _start + size;
        _end_of_storage = _finish;
    }

    //拷贝构造
    My_vector(const My_vector<T>& v):_start(new T[v.size()])
    {
        int size = v.size();
        for (int i = 0; i < size; i++)
        {
            _start[i] = v[i];
        }
        _finish = _start + size;
        _end_of_storage = _finish;
    }

    //重载=
    My_vector<T>& operator=(My_vector<T> v)
    {
        _start = new T[v.size()];
        for (int i = 0; i < v.size(); i++)
        {
            _start[i] = v[i];
        }
        _finish = _start + v.size();
        _end_of_storage = _finish;
        return *this;
    }

    //析构函数
    ~My_vector()
    {
        if (_start)
        {
            delete[]_start;
            _start = nullptr;
            _finish = nullptr;
            _end_of_storage = nullptr;
        }
    }

/*-------------------------------------迭代器相关------------------------------------------*/
    //获取容器起始位置的迭代器
    _iterator begin() { return _start; }
    _const_iterator begin() const { return _start; }

    //获取容器最后一个元素的下一个位置的迭代器
    _iterator end() { return _finish; }
    _const_iterator end() const { return _finish; }

    //获取容器逆向起始位置的迭代器
    _iterator rbegin() { return _finish - 1; }
    _const_iterator rbegin() const { return _finish - 1; }

    //获取容器逆向最后一个元素的前一个位置的迭代器
    _iterator rend() { return _start - 1; }
    _const_iterator rend() const { return _start - 1; }

/*-------------------------------------容量相关------------------------------------------*/
    //获取容器size大小
    int size() const { return _finish - _start; }
    
    //获取容器容量大小
    int capacity() const { return _end_of_storage - _start; }
    
    //判空
    bool empty() const { return _start == _finish; }

    //重新设置size
    void resize(int newsize, const T& val = T())
    {
        int oldsize = this->size();
        if (newsize <= oldsize)
        {
            _finish = _start + newsize;
        }
        else
        {
            reserve(newsize);
            while (_finish != _end_of_storage)
            {
                *_finish = val;
                ++_finish;
            }
        }
    }

    //重新设置容量
    void reserve(int newstorage)
    {
        int oldstorage = this->capacity();
        if (newstorage > oldstorage)
        {
            T* new_start = new T[newstorage];
            if (new_start)
            {
                int size = this->size();
                int i = 0;
                while (i < size)
                {
                    new_start[i] = _start[i];
                    i++;
                }
                delete[]_start;
                _start = new_start;
                _finish = _start + size;
                _end_of_storage = _start + newstorage;
            }
        }
    }

/*-------------------------------------元素访问------------------------------------------*/
    //获取容器第一个元素
    T& front() { return *_start; }
    const T& front() const { return *_start; }

    //获取容器最后一个元素
    T& back() { return *(_finish - 1); }
    const T& back() const { return *(_finish - 1); }

    //重载[]
    T& operator[](const int index)
    {
        if (index < size())
        {
            return _start[index];
        }
    }
    const T& operator[](const int index) const
    {
        if (index < size())
        {
            return _start[index];
        }
    }

/*-------------------------------------元素修改------------------------------------------*/
    //尾插
    void push_back(const T& val)
    {
        int size = this->size();
        if (size == capacity())
        {
            if (size == 0)
            {
                reserve(1);
            }
            else if (size == 1)
            {
                reserve(2);
            }
            else
            {
                reserve(size * 1.5);
            }
        }
        *_finish = val;
        ++_finish;
    }

    //尾删
    void pop_back()
    {
        if (!empty())
        {
            --_finish;
        }
    }

    //任意位置插入
    _iterator insert(_iterator pos, const T& val)
    {
        //插入位置是否合法
        assert(!(pos < _start || pos > _finish));
        //是否需要扩容
        int size = this->size();
        if (size == capacity())
        {
            if (size == 0)
            {
                reserve(1);
            }
            else if (size == 1)
            {
                reserve(2);
            }
            else
            {
                reserve(size * 1.5);
            }
        }
        //插入位置及以后元素全部向后移动一位
        _iterator it = _finish;
        while (it != pos)
        {
            *it = *(it - 1);
            --it;
        }
        //插入元素
        *it = val;
        //__finish也后移一位
        _finish++;
        //返回新插入元素的迭代器
        return pos;
    }

    //删除元素
    _iterator erase(_iterator pos)
    {
        //删除位置是否合法
        assert(!this->empty() && !(pos < _start || pos >= _finish));
        _iterator it = pos;
        //删除位置之后位置向前移动一位
        while (it != _finish)
        {
            *(it - 1) = *it;
            ++it;
        }
        //并且_finish也向前移动一位
        --_finish;
        //返回删除元素的下一个元素的迭代器
        return pos;
    }

    void clear()
    {
        _finish = _start;
    }
};
### C++ STL Vector 的使用方法及示例 #### 1. 基本概念 `std::vector` 是 C++ 标准模板库(STL)中的一个重要组件,属于一种动态数组容器。与传统静态数组相比,`std::vector` 可以在运行时动态调整其大小[^3]。 为了使用 `std::vector`,需要包含头文件 `<vector>` 并显式实例化模板类[^2]。 #### 2. 创建和初始化 以下是创建并初始化 `std::vector` 的几种常见方式: ```cpp #include <iostream> #include <vector> int main() { // 方式一:默认构造函数 std::vector<int> v1; // 方式二:指定初始容量 std::vector<int> v2(5); // 初始化为五个0 // 方式三:指定初始值 std::vector<int> v3(5, 10); // 初始化为五个10 // 方式四:通过另一个向量初始化 std::vector<int> v4(v3); // 方式五:从数组初始化 int arr[] = {1, 2, 3}; std::vector<int> v5(arr, arr + sizeof(arr)/sizeof(int)); return 0; } ``` #### 3. 遍历元素 可以通过迭代器或者范围循环来遍历 `std::vector` 中的元素[^1]。 ```cpp #include <iostream> #include <vector> int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; // 方法一:使用迭代器 for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; // 方法二:使用范围for循环 for (const auto& elem : vec) { std::cout << elem << " "; } return 0; } ``` #### 4. 动态调整大小 `std::vector` 支持动态扩展和收缩,常用的方法有 `push_back()`、`pop_back()`、`resize()` 和 `reserve()`[^4][^5]。 - **`push_back(value)`**: 向向量末尾添加新元素。 - **`pop_back()`**: 删除向量最后一个元素。 - **`resize(new_size)`**: 调整向量大小至 `new_size`。 - **`reserve(size)`**: 预留至少 `size` 大小的空间。 示例如下: ```cpp #include <iostream> #include <vector> int main() { std::vector<int> vec; // 添加元素 vec.push_back(1); vec.push_back(2); // 扩展大小 vec.resize(5, 0); // 将vec扩展到5个元素,默认填充为0 // 预留空间 vec.reserve(10); // 至少预留10个位置 // 移除最后元素 vec.pop_back(); for (const auto& elem : vec) { std::cout << elem << " "; } return 0; } ``` #### 5. 访问元素 可以使用索引运算符 `[ ]` 或者成员函数 `at(index)` 来访问向量中的元素。 ```cpp #include <iostream> #include <vector> int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; // 使用 [] 运算符 std::cout << "First element: " << vec[0] << std::endl; // 使用 at() 函数 try { std::cout << "Third element: " << vec.at(2) << std::endl; } catch (const std::out_of_range& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逐梦的白鹰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值