【C++】vector

vector简介

  1. vector是一个表示可变大小数组的序列容器
  2. vector的底层存储和数组类似,采用连续的空间存储数据。这就意味着vector支持下标访问元素
  3. vector的空间大小是动态可变的,当新元素插入,空间不够时,它可以自动扩容
  4. vector会分配一些额外的空间来适应数据的增长,所以vector使用的空间比实际需要的空间要大
  5. 与其他动态序列容器相比,vector访问元素的效率较高,尾插尾删数据的效率也很不错;但是对于其他位置的修改,效率就很低了

vector类的常用接口

在使用容器时,查询文档是必不可少的:vector相关文档

下面列举一些常用的接口

构造

接口接口说明
vector()无参构造
vector(size_type n, const value_type& val = value_type ())构造并初始化 n 个 val
vector(const vector& v)拷贝构造
vector(InputIterator first, InputIterator last)使用迭代器进行初始化构造
void test1()
{
        // 无参
        vector<int> v1;
        // n val
        vector<int> v2(10, 1);
        // 拷贝构造
        vector<int> v3(v2);
        // 迭代器区间构造
        string s("abcd");
        vector<int> v4(s.begin(), s.end());

        for (auto& e : v1)
                cout << e << " ";
        cout << endl;
        
        for (auto& e : v2)
                cout << e << " ";
        cout << endl;
        
        for (auto& e : v3)
                cout << e << " ";
        cout << endl;
        
        for (auto& e : v4)
                cout << e << " ";
        cout << endl;
}

在这里插入图片描述

迭代器

接口接口说明
begin()获取第一个数据位置的 iterator
end()获取最后一个数据的下一个位置的 iterator
rbegin()获取最后一个数据位置的 reverse_iterator
rend()获取第一个数据前一个位置的 reverse_iterator

在这里插入图片描述

Capacity

接口接口说明
size()获取数据个数。返回值为容器中当前实际存储的元素个数。
capacity()获取容量大小。表示在不重新分配内存的情况下,容器可以容纳的元素数量。
empty()判断是否为空。如果容器中没有元素,则返回 true,否则返回 false。
resize()改变 vector 的 size。可以指定新的大小,如果新大小小于当前大小,容器会删除多余的元素;如果新大小大于当前大小,新添加的元素会进行值初始化(对于基本类型初始化为 0,对于类类型会调用默认构造函数)。
reserve()改变 vector 的 capacity。可以预先分配一定的内存空间,避免在添加元素时频繁进行内存重新分配操作。如果指定的容量小于当前容量,则此函数不做任何操作。

增删查改

接口接口说明
push_back()尾插
pop_back()尾删
find(算法模块实现)查找。查找特定元素,返回指向该元素的迭代器,如果未找到则返回尾迭代器。
insert在指定位置之前插入 val。可以插入单个元素或一段范围的元素。
erase删除 position 位置的数据。可以删除单个位置的元素,也可以删除一个范围内的元素。
swap交换两个 vector 的数据空间。快速交换两个向量的内容,而不需要逐个元素复制。
operator[]像数组一样访问。可以通过下标访问向量中的元素,但不进行边界检查,使用时需确保下标在合法范围内。

vector类的模拟实现

模板类

因为vector中可以存储不同类型的数据:内置类型、自定义类型,所以我们要将vector写成模板类

template <class T>
class vector
{};

成员变量

在vector中,许多功能都要依赖迭代器来实现,所以迭代器是很重要的

vector的迭代器底层是原生指针,所以vector的iterator可以使用 T* 来实现

template <class T>
class vector
{
public:
        typedef T* iterator;
        typedef const T* const_iterator;
};

在string的模拟实现中,我们用到了三个成员变量:

  • char* _str:字符数组的地址,用来存储字符串
  • size_t _size:用来表示字符串的实际长度
  • size_t _capacity:用来表示空间的总大小

模拟实现vector,我们用的三个变量和string的类似,只不过用的都是迭代器,而vector的迭代器底层就是原生指针,也就是我们的三个成员变量都是指针

  • iterator _start:指向第一个数据
  • iterator _finish:指向最后一个数据的下一个位置
  • iterator _endofstorage:指向空间的末尾

虽然换了一种形式,但是vector的成员变量和string的成员变量代表的含义是类似的

在这里插入图片描述

搭一个框架

先把无参构造、size()、capacity()、operator[]、push_back()这几个功能实现,搭一个能跑的框架

无参构造

不传参数构造一个对象,那么对象中就是空的,所以先不开空间,直接给三个成员变量赋值为空,等插入数据时再做开空间等操作

可以在声明时给成员变量缺省值,这里的缺省值是给初始化列表准备的,这样进入构造函数,走初始化列表时,就不用我们手动写了

template <class T>
class vector
{
public:
        typedef T* iterator;
        typedef const T* const_iterator;

        vector() {}
private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
};

size && capacity

size_type size() const;
size_type capacity() const;
  • 两指针相减即可得到长度
  • size = _finish - _start
  • capacity = _endofstorage - _start
size_t size() const
{
        return _finish - _start;
}

size_t capacity() const
{
        return _endofstorage - _start;
}

operator[]

      reference operator[] (size_type n);
const_reference operator[] (size_type n) const;

返回指定下标的元素的引用

  • 可以加一个断言,防止越界操作
  • 因为底部是数组存储,所以直接返回 _start[n] 即可
T& operator[](size_t n)
{
        assert(n >= 0);
        assert(n < size());
        return _start[n];
}
const T& operator[](size_t n) const
{
        assert(n >= 0);
        assert(n < size());
        return _start[n];
}

push_back()

void push_back (const value_type& val);
  • 在插入数据之前,要检查空间是否已满,满了就要进行扩容。先在这里实现一个扩容,后面写了reserve再替换
  • 扩容时,如果原来的对象为空,就给 4 个初始空间;否则就 2 倍扩容。拷贝旧空间的数据到新空间时,可以使用 memcpy

在这里插入图片描述

  • 在尾部插入数据,更新 _finish
void push_back(const T& val)
{
        // 检查扩容
        if (_finish == _endofstorage)
        {
                size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();

                // 申请新空间,拷贝旧数据
                T* tmp = new T[newcapacity];
                memcpy(tmp, _start, sizeof(T) * size());
                delete[] _start;
                
                // 更新数据
                _start = tmp;
                _finish = tmp + size();
                _endofstorage = tmp + newcapacity;
        }

        // 插入数据
        *_finish = val;
        ++_finish;
}

基本的架子搭建完成,先写一个打印vector的函数,测试一下插入数据

template <class T>
void PrintVector(const vector<T>& v)
{
        for (int i = 0; i < v.size(); i++)
                cout << v[i] << " ";
        cout << endl;
}

测试数据

void test1()
{
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);

        PrintVector(v1);
}

测试结果:

在这里插入图片描述

程序出错了,哪一步出错了呢?进入调试,发现问题出在 push_back 中,尾插数据时出现了空指针错误

在这里插入图片描述

虽然我们构造了一个空的vector对象,_finish应该是空指针,但是经过扩容后_finish就不应该是空了。那么问题就是出在扩容了,再次进入调试,看看申请空间后,三个成员变量是否更新成功

在这里插入图片描述

可以看到,执行完扩容的代码,_start和_endofstorage都不再是空指针了,唯独_finish还是空指针,而更新_finish的语句是这一句:

_finish = tmp + size();

tmp肯定是没有问题的,那么答案显而易见,问题出在size()

size_t size() const
{
        return _finish - _start;
}

原来是我们更新了_start的位置,但是 _finish 还留在原地,那么得到的size肯定是错误的

在这里插入图片描述

要解决这个问题,有两种办法

  1. 先更新_finish,再更新_start
// 更新数据
_finish = tmp + size();
_start = tmp;
_endofstorage = tmp + newcapacity;
  1. 一开始就记录旧的size,用旧size更新_finish,这里采用这个方法
// 更新数据
size_t old_size = size();
// ...
_start = tmp;
_finish = tmp + old_size;
_endofstorage = tmp + newcapacity;

测试:

在这里插入图片描述

既然完善了扩容,那接下来就写容量相关的接口吧

Capacity

size && capacity

size_t size() const
{
        return _finish - _start;
}

size_t capacity() const
{
        return _endofstorage - _start;
}

empty

bool empty() const;
  • 当 _start 和 _finish 指向同一个位置时,说明空间没有数据
bool empty() const
{
        return _start == _finish;
}

reserve

void reserve (size_t n);

上面我们写 push_back 时已经完成了 reserve,直接拿来用

void reserve(size_t n)
{
        if (n > capacity())
        {
                // 申请新空间,拷贝旧数据
                T* tmp = new T[n];
                memcpy(tmp, _start, sizeof(T) * size());

                // 更新数据
                size_t old_size = size();
                _start = tmp;
                _finish = tmp + old_size;
                _endofstorage = tmp + n;
        }
}

resize

void resize(size_t n, const T& val = T());
  • 当 n <= size() 时,需要将有效数据删除到 n 个。不需要真的删除数据,只需要更新 _finish 即可
  • 当 n > size() 时,需要填充数据为 val,这里的参数 val 有可能是自定义类型,所以缺省值是一个无参的匿名对象内置类型也有构造函数,调用无参构造时会对内置类型对象初始化,例如整型初始化为0,指针初始化为nullptr
void resize(size_t n, const T& val = T())
{
        if (n <= size())
        {
                // 删除数据
                _finish = _start + n;
        }
        else
        {
                // 填充数据
                reserve(n);

                while (_finish < _start + n)
                {
                        *_finish = val;
                        ++_finish;
                }
        }
}

在这里插入图片描述

迭代器

这里只实现begin()和end()以及它们的const版本

begin()

      iterator begin();
const_iterator begin() const;

获取第一个数据位置的迭代器,也就是获取第一个数据的指针

iterator begin()
{
        return _start;
}
const_iterator begin() const
{
        return _start;
}

end()

      iterator end();
const_iterator end() const;

获取最后一个数据下一个位置的迭代器

iterator end()
{
        return _finish;
}
const_iterator end() const
{
        return _finish;
}

测试:

在这里插入图片描述

增删查改

push_back

void push_back(const T& val)
{
        // 检查扩容
        if (_finish == _endofstorage)
        {
                size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                reserve(newcapacity);
        }

        // 插入数据
        *_finish = val;
        ++_finish;
}

pop_back

void pop_back();
  • 尾删一个元素,只需_finish减一即可
  • 可以加一个断言,数据为空时不可以删除
void pop_back()
{
        assert(!empty());
        --_finish;
}

测试:

在这里插入图片描述

insert

iterator insert (iterator pos, const T& val);

在pos位置插入一个数据

  • 加一个断言,防止越界,insert也可以支持头插尾插
  • 在插入数据从之前,需要检查扩容
  • 然后就需要挪动数据了,将pos位置及其后面的数据向后挪动一个单位
  • 挪动完成后,更新数据即可
  • 返回新插入数据的位置的迭代器,也就是pos
iterator insert(iterator pos, const T& val)
{
        assert(pos >= _start);
        assert(pos <= _finish);

        // 检查扩容
        if (_finish == _endofstorage)
        {
                size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                reserve(newcapacity);
        }

        // 挪动数据
        iterator cur = end();
        while (cur > pos)
        {
                *cur = *(cur - 1);
                --cur;
        }

        // 更新数据
        *pos = val;
        ++_finish;

        return pos;
}

测试:

在这里插入图片描述

但是这里有个隐藏bug,多插入几个数据就会出错

在这里插入图片描述

这是为什么呢?这两次测试的区别就是:第二次测试插入的数据较多,发生了扩容。怎么又是扩容的问题??

我们之前遇到的问题是空间发生了更新,然而指向原空间的指针并未更新,这次的问题也是这样:

  • pos 指向原空间
  • 如果发生了扩容,pos位置未更新,后面又使用pos进行操作,大概率会发生错误

在这里插入图片描述

  • 所以如果需要扩容,先记录下pos相对_start的相对位置,扩容完成后更新pos
iterator insert(iterator pos, const T& val)
{
        assert(pos >= _start);
        assert(pos <= _finish);

        // 检查扩容
        if (_finish == _endofstorage)
        {
                // pos相对位置
                size_t len = pos - _start;

                size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                reserve(newcapacity);

                // 更新pos
                pos = _start + len;
        }

        // 挪动数据
        iterator cur = end();
        while (cur > pos)
        {
                *cur = *(cur - 1);
                --cur;
        }

        // 更新数据
        *pos = val;
        ++_finish;

        return pos;
}

测试:

在这里插入图片描述

erase

iterator erase (iterator pos);

删除pos位置的数据

  • 断言,防止越界
  • 将 pos 后面的数据向前挪动一个单位
  • 返回被删除数据的后一个数据的迭代器,也就是pos
iterator erase(iterator pos)
{
        assert(pos >= _start);
        assert(pos < _finish);

        // 挪动数据
        iterator cur = pos + 1;
        while (cur != _finish)
        {
                *(cur - 1) = *cur;
                ++cur;
        }
        --_finish;

        return pos;
}

测试:

在这里插入图片描述

实现了 insert 和 erase,就可以复用代码来实现 push_back 和 pop_back

void push_back(const T& val)
{
        insert(end(), val);
}

void pop_back()
{
        erase(end() - 1);
}

swap

两个vector对象的交换,如果调用算法库的swap,就是这样的:

template <class T> void swap ( T& a, T& b )
{
  T c(a); a=b; b=c;
}

拷贝构造一个临时对象c,又经历了两次赋值拷贝,一共经历了3次拷贝

如果T是比较复杂的自定义类型,3次拷贝消耗有点大,没有必要。我们只需要交换两个对象内部的指针,就可以达到交换数据的目的

在这里插入图片描述

void swap(vector<T>& v)
{
        std::swap(_start, v._start);
        std::swap(_finish, v._finish);
        std::swap(_endofstorage, v._endofstorage);
}

测试:

在这里插入图片描述

完善构造函数

除了无参构造,我们还有几个构造函数没写

接口接口说明
vector()无参构造
vector(size_type n, const value_type& val = value_type ())构造并初始化 n 个 val
vector(const vector& v)拷贝构造
vector(InputIterator first, InputIterator last)使用迭代器进行初始化构造

迭代器区间构造

vector(InputIterator first, InputIterator last)

先来看最难的,其实也不难,就是之前没用过,有点陌生而已

我们可以使用另一个对象的迭代器区间进行构造,例如使用string对象的迭代器区间

在这里插入图片描述

  • 只需遍历取出区间中的元素,然后调用vector对象的尾插即可
  • 迭代器可能是string的迭代器,也可能是vector或者其他容器的,所以这里要使用函数模板
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
        while (first != last)
        {
                push_back(*first);
                ++first;
        }
}

测试:

在这里插入图片描述

n value

vector(size_t n, const T& val = T())

构造并初始化 n 个 val

  • 调用 n 次尾插即可
vector(size_t n, const T& val = T())
{
        for (int i = 0; i < n; i++)
                push_back(val);
}

测试:

在这里插入图片描述

程序编译错误,发现和 InputIterator 有关,为什么我们调用 n-val 的构造,会和迭代器区间构造有关系呢?——因为参数类型导致编译器调用的是函数模板

  • 创建对象时,传的参数是(10, 1),参数类型是 int int
  • n-val 构造函数的参数类型是 size_t T
  • 迭代器构造函数模板的参数则是 InputIterator InputIterator

在编译器看来,迭代器函数模板的参数可以推演成 int int,更加匹配,所以就调用函数模板

我们可以把第一个参数转换为 size_t 类型,再测试一下:

在这里插入图片描述

运行成功,此时我们传的参数类型是 size_t int,和 n-val 函数的参数类型更加匹配。但是我们不能每次都这样传参数吧,太麻烦了

解决办法就是重载一个参数类型是 int int 的 n-val 构造函数

vector(size_t n, const T& val = T())
{
        for (int i = 0; i < n; i++)
                push_back(val);
}
vector(int n, const T& val = T())
{
        for (int i = 0; i < n; i++)
                push_back(val);
}

测试:

在这里插入图片描述

拷贝构造

vector(const vector& v)

已存在的对象来构造一个新的对象

这里就直接使用现代写法了

  • 现代写法:不用我们手动开空间然后拷贝数据。直接将 v 的数据尾插到当前对象
vector(const vector<T>& v)
{
        reserve(v.capacity());
        for (auto& e : v)
                push_back(e);
}

测试:

在这里插入图片描述

析构函数

差点就把析构函数就给忘了

~vector()
{
        delete[] _start;
        _start = _finish = _endofstorage = nullptr;
}

赋值拷贝 operator=

vector& operator= (const vector& x);

将已存在的对象赋值给另一个已存在对象

这里就不按照上面的函数头写了,使用现代写法

  • 传值传参,也就是拷贝构造一个临时对象v
  • 调用swap,将 *this 与 v 的数据进行交换
vector<T>& operator= (vector<T> v)
{
        swap(v);
        return *this;
}

测试:

在这里插入图片描述

memcpy的浅拷贝问题

我们在reserve的实现中,拷贝数据使用的是 memcpy 函数,它使用的是浅拷贝。如果vector中存的是自定义类型,且自定义类型会申请空间的话,那么析构时就会出现问题

例如使用string类型

在这里插入图片描述

目前来看代码可以正常运行,但是一旦扩容就会出现问题

在这里插入图片描述

以下是扩容之前的空间和扩容之后的空间,memcpy只是将旧空间中的数据拷贝到新空间,并不会把string指向的字符串也拷贝过来,这时旧空间和新空间的string对象指向同一块空间

在这里插入图片描述

扩容完毕后,我们需要调用 delete[] 释放旧空间,以下是delete[]的过程:

  • 在 free 旧空间之前,会调用string对象的析构函数,释放string对象申请的空间

在这里插入图片描述

  • 之后再调用 free 释放vector对象的空间

在这里插入图片描述

也就是说,当我们 delete[] 旧空间后,新空间中string指向的空间也已经被释放了

在这里插入图片描述

当调用 v1 的析构函数时,实际上string对象的空间已经被释放,会发生野指针问题

解决方法就是不用memcpy拷贝数据,直接遍历新开的空间和旧空间,将旧空间的数据赋值给新空间。如果数据是自定义类型,就会调用自定义类型的赋值拷贝,默认是深拷贝

void reserve(size_t n)
{
        if (n > capacity())
        {
                size_t old_size = size();
                // 申请新空间,拷贝旧数据
                T* tmp = new T[n];
                // memcpy(tmp, _start, sizeof(T) * size());
                for (int i = 0; i < old_size; i++)
                        tmp[i] = _start[i];
                delete[] _start;

                // 更新数据
                _start = tmp;
                _finish = tmp + old_size;
                _endofstorage = tmp + n;
        }
}

测试:

在这里插入图片描述

迭代器失效

假设有一个迭代器pos,当我们在pos位置插入或者删除数据后,pos就会失效

  1. 如果插入数据时发生了扩容,那么迭代器 pos 指向的空间就会被释放掉,此时 pos 就不可以再使用了

在这里插入图片描述

  1. 虽然删除数据不会发生空间的改变,但是 pos 位置的数据被删除,我们不能再通过 pos 得到原来的数据了,这也是迭代器失效

使用失效的迭代器是有风险的,有什么方法可以规避呢?

  1. 迭代器失效后,就不要再使用了
  2. 如果一定要使用失效的迭代器,那就更新迭代器后再使用

如何更新迭代器呢?

  • insert 插入数据成功后,会返回新插入的第一个数据的迭代器

在这里插入图片描述

  • erase 删除数据后,会返回被删除数据的后一个位置的迭代器

在这里插入图片描述
在插入或者删除数据后,及时接收 insert 和 erase 的返回值来更新迭代器

代码

#pragma once

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

namespace ns1
{
        template <class T>
        class vector
        {
        public:
                typedef T* iterator;
                typedef const T* const_iterator;

                vector() {}

                ~vector()
                {
                        delete[] _start;
                        _start = _finish = _endofstorage = nullptr;
                }

                template <class InputIterator>
                vector(InputIterator first, InputIterator last)
                {
                        while (first != last)
                        {
                                push_back(*first);
                                ++first;
                        }
                }

                vector(size_t n, const T& val = T())
                {
                        for (int i = 0; i < n; i++)
                                push_back(val);
                }
                vector(int n, const T& val = T())
                {
                        for (int i = 0; i < n; i++)
                                push_back(val);
                }

                vector(const vector<T>& v)
                {
                        reserve(v.capacity());
                        for (auto& e : v)
                                push_back(e);
                }

                vector<T>& operator= (vector<T> v)
                {
                        swap(v);
                        return *this;
                }

                size_t size() const
                {
                        return _finish - _start;
                }

                size_t capacity() const
                {
                        return _endofstorage - _start;
                }

                bool empty() const
                {
                        return _start == _finish;
                }

                void reserve(size_t n)
                {
                        if (n > capacity())
                        {
                                size_t old_size = size();
                                // 申请新空间,拷贝旧数据
                                T* tmp = new T[n];
                                // memcpy(tmp, _start, sizeof(T) * size());
                                for (int i = 0; i < old_size; i++)
                                        tmp[i] = _start[i];
                                delete[] _start;

                                // 更新数据
                                _start = tmp;
                                _finish = tmp + old_size;
                                _endofstorage = tmp + n;
                        }
                }

                void resize(size_t n, const T& val = T())
                {
                        if (n <= size())
                        {
                                // 删除数据
                                _finish = _start + n;
                        }
                        else
                        {
                                // 填充数据
                                reserve(n);

                                while (_finish < _start + n)
                                {
                                        *_finish = val;
                                        ++_finish;
                                }
                        }
                }

                T& operator[](size_t n)
                {
                        assert(n >= 0);
                        assert(n < size());
                        return _start[n];
                }
                const T& operator[](size_t n) const
                {
                        assert(n >= 0);
                        assert(n < size());
                        return _start[n];
                }

                iterator begin()
                {
                        return _start;
                }
                const_iterator begin() const
                {
                        return _start;
                }

                iterator end()
                {
                        return _finish;
                }
                const_iterator end() const
                {
                        return _finish;
                }

                void push_back(const T& val)
                {
                         检查扩容
                        //if (_finish == _endofstorage)
                        //{
                        //        size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                        //        reserve(newcapacity);
                        //}

                         插入数据
                        //*_finish = val;
                        //++_finish;

                        insert(end(), val);
                }

                void pop_back()
                {
                        //assert(!empty());
                        //--_finish;
                        erase(end() - 1);
                }

                iterator insert(iterator pos, const T& val)
                {
                        assert(pos >= _start);
                        assert(pos <= _finish);

                        // 检查扩容
                        if (_finish == _endofstorage)
                        {
                                // pos相对位置
                                size_t len = pos - _start;

                                size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                                reserve(newcapacity);

                                // 更新pos
                                pos = _start + len;
                        }

                        // 挪动数据
                        iterator cur = end();
                        while (cur > pos)
                        {
                                *cur = *(cur - 1);
                                --cur;
                        }

                        // 更新数据
                        *pos = val;
                        ++_finish;

                        return pos;
                }

                iterator erase(iterator pos)
                {
                        assert(pos >= _start);
                        assert(pos < _finish);

                        // 挪动数据
                        iterator cur = pos + 1;
                        while (cur != _finish)
                        {
                                *(cur - 1) = *cur;
                                ++cur;
                        }
                        --_finish;

                        return pos;
                }

                void swap(vector<T>& v)
                {
                        std::swap(_start, v._start);
                        std::swap(_finish, v._finish);
                        std::swap(_endofstorage, v._endofstorage);
                }
        private:
                iterator _start = nullptr;
                iterator _finish = nullptr;
                iterator _endofstorage = nullptr;
        };

        template <class T>
        void PrintVector(const vector<T>& v)
        {
                for (int i = 0; i < v.size(); i++)
                        cout << v[i] << " ";
                cout << endl;
        }
        void test1()
        {
                vector<int> v1;
                v1.push_back(1);
                v1.push_back(2);
                v1.push_back(3);
                v1.push_back(4);
                v1.push_back(5);

                PrintVector(v1);
        }
        
        void test2()
        {
                vector<int> v1;
                v1.push_back(1);
                v1.push_back(2);
                v1.push_back(3);
                v1.push_back(4);
                PrintVector(v1);
                cout << v1.size() << endl;
                cout << v1.capacity() << endl;
                // 填充
                v1.resize(20);
                PrintVector(v1);
                cout << v1.size() << endl;
                cout << v1.capacity() << endl;
                // 删除
                v1.resize(2);
                PrintVector(v1);
                cout << v1.size() << endl;
                cout << v1.capacity() << endl;
        }
        void test3()
        {
                vector<int> v1;
                v1.push_back(1);
                v1.push_back(2);
                v1.push_back(3);
                v1.push_back(4);

                // 迭代器遍历
                vector<int>::iterator it1 = v1.begin();
                for (; it1 != v1.end(); it1++)
                        cout << *it1 << " ";
                cout << endl;
                // 范围 for
                for (auto& e : v1)
                        cout << e << " ";
                cout << endl;
        }
        
        void test4()
        {
                vector<int> v1;
                v1.push_back(1);
                v1.push_back(2);
                v1.push_back(3);
                v1.push_back(4);
                PrintVector(v1);

                v1.pop_back();
                PrintVector(v1);
                v1.pop_back();
                PrintVector(v1);
                v1.pop_back();
                PrintVector(v1);
                v1.pop_back();
                PrintVector(v1);
                v1.pop_back();
                PrintVector(v1);
        }

        void test5()
        {
                vector<int> v1;
                v1.push_back(1);
                PrintVector(v1);
                // 头插
                v1.insert(v1.begin(), 10);
                PrintVector(v1);
                // 尾插
                v1.insert(v1.end(), 30);
                PrintVector(v1);
                // 中间插
                v1.insert(v1.begin() + 1, 20);
                PrintVector(v1);
                // 尾插
                v1.insert(v1.end(), 100);
                PrintVector(v1);
                // 尾插
                v1.insert(v1.end(), 100);
                PrintVector(v1);
                // 尾插
                v1.insert(v1.end(), 100);
                PrintVector(v1);
        }

        void test6()
        {
                vector<int> v1;
                v1.push_back(1);
                v1.push_back(2);
                v1.push_back(3);
                v1.push_back(4);
                v1.push_back(5);
                v1.push_back(6);
                PrintVector(v1);

                // 头删
                v1.erase(v1.begin());
                PrintVector(v1);
                // 尾删
                v1.erase(v1.end()-1);
                PrintVector(v1);
                // 中间删
                v1.erase(v1.begin()+1);
                PrintVector(v1);
        }

        void test7()
        {
                vector<int> v1;
                v1.push_back(1);
                v1.push_back(2);
                v1.push_back(3);
                v1.push_back(4);
                PrintVector(v1);


                vector<int> v2;
                v2.push_back(5);
                v2.push_back(6);
                v2.push_back(7);
                v2.push_back(8);
                PrintVector(v2);

                v1.swap(v2);
                PrintVector(v1);
                PrintVector(v2);
        }

        void test8()
        {
                string s1 = "abcd";
                vector<char> v1(s1.begin(), s1.end());
                PrintVector(v1);
        }

        void test9()
        {
                /*vector<int> v1(10, 1);
                vector<int> v2(v1);*/

                vector<int> v1(10, 1);
                vector<int> v2(10, 2);
                v1 = v2;
                PrintVector(v1);
                PrintVector(v2);
        }

        void test10()
        {
                vector<string> v1;
                v1.push_back("一");
                v1.push_back("二");
                v1.push_back("三");
                v1.push_back("四");
                v1.push_back("五");

                PrintVector(v1);
        }
}
);
        }

        void test7()
        {
                vector<int> v1;
                v1.push_back(1);
                v1.push_back(2);
                v1.push_back(3);
                v1.push_back(4);
                PrintVector(v1);


                vector<int> v2;
                v2.push_back(5);
                v2.push_back(6);
                v2.push_back(7);
                v2.push_back(8);
                PrintVector(v2);

                v1.swap(v2);
                PrintVector(v1);
                PrintVector(v2);
        }

        void test8()
        {
                string s1 = "abcd";
                vector<char> v1(s1.begin(), s1.end());
                PrintVector(v1);
        }

        void test9()
        {
                /*vector<int> v1(10, 1);
                vector<int> v2(v1);*/

                vector<int> v1(10, 1);
                vector<int> v2(10, 2);
                v1 = v2;
                PrintVector(v1);
                PrintVector(v2);
        }

        void test10()
        {
                vector<string> v1;
                v1.push_back("一");
                v1.push_back("二");
                v1.push_back("三");
                v1.push_back("四");
                v1.push_back("五");

                PrintVector(v1);
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿洵Rain

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

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

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

打赏作者

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

抵扣说明:

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

余额充值