STL-vector

什么是vector

vector是可变大小的数组,支持快速随机访问,在尾部之外的位置插入或者删除元素可能很慢。

为什么会有vector?

      vector的数据安排以及操作方式,与数组非常相似,两者的唯一差别在于空间运用的灵活性。数组是静态空间,一旦分配空间后就不能改变其大小,如果想要扩容或者是减容,操作比较繁琐。vector是动态空间,随着元素的加入,他的内部机制会自动扩充空间以容纳新元素。因此vector的运用对于内存的利用与使用的灵活性有很大的提高,我们再也不必害怕空间不足而一开始就分配一个大数组了。
在这里插入图片描述

vector的迭代器

      vector维护一个线性空间,所以不论元素的型别如何,普通指针都可以作为vector的迭代器,因为迭代器的功能,如operaroe*, operator->, operator++, operator–, operator+, operator-, operator+=, operator-=,这些操作普通指针天生具备,vector支持随机存取,而普通指针正有着这样的能力。所以vector提供的是随机访问迭代器。

vector的数据结构

      vector所采取的数据结构非常简单,线性连续空间,迭代器_Myfirst和_Mylast分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器_Myend指向整块连续内存空间的尾端。
      为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以备将来可能的扩充,这便是容量的概念。换句话说,一个vector的容量永远大于或者等于其有效长度,一旦容量等于其有效长度,便是满载,下次再有新增元素,整个vector容器就得进行扩容。
      所谓的动态增加大小,并不是原空间之后连续开辟空间(因为无法保证源空间之后尚有可分配内存),而是一块更大的内存空间,然后将原数据拷贝到新空间,并释放原空间。因此,对vector的任何操作,一旦引起空间的重新分配,指向原vector的所有迭代器都就失效了。

构造函数

函数名称函数功能
vector采用模板实现类实现,默认构造函数
vector(v.begin(), v.end())将v[begin(), end())区间中的元素拷贝给本身
vector(n, elem)构造函数将n个elem拷贝给本身
vector(const vector &vec)拷贝构造函数
int arr[] = {2,3,4,1,9};
vector<int> v1(arr, arr + sizeof(arr) / sizeof(int));

赋值操作

函数名称函数功能
assign(beg, end)将[beg, end)区间中的数据拷贝赋值给本身
assign(n, elem)将n个elem拷贝赋值给本身
vector& operator=(const vector &vec)重载等号操作符
swap(vec)将vec与本身的元素互换
// 巧用swap收缩空间
void test03()
{
    vector<int> v;
    for(int i = 0; i < 100000; i++)
    {
        v.push_back(i);
    }
    
    cout << "v的容量 " << v.capacity() << endl;
    cout << "v的大小 " << v.size() << endl;

    v.resize(3);
    cout << "v的容量 " << v.capacity() << endl;
    cout << "v的大小 " << v.size() << endl;

    // 巧用swap
    // 默认构造匿名对象,然后交换空间,匿名对象在执行完改行代码后就
    // 被释放掉了,所以130000也被释放了
    vector<int> (v).swap(v);

    cout << "v的容量 " << v.capacity() << endl;
    cout << "v的大小 " << v.size() << endl;

}

迭代器操作

函数名称函数功能
begin()获取第一个数据位置的迭代器
end()获取最后一个数据的下一个位置的迭代器
rbegin()获得最后一个数据位置的反向迭代器
rend()获得第一个位置的前一个位置的反向迭代器
cbegin()获得第一个数据位置的const迭代器
cend()获得最后一个数据的下一个位置的const迭代器

容量操作

函数名称函数功能
size()返回容器中元素的个数
empty()判断容器是否为空
resize(int num)重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
capacity()容器的容量
reserve(int len)容器预留len个元素长度,预留位置不初始化,元素不可访问

      reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。如果指定的参数小于当前的capacity,则不会产生任何效果。只有当参数大于capacity时才有意义。
      capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增加的。不要固化的认为,顺序表增容都是2倍。这里是存在问题的!,当我们使用insert方法完成数据插入的时候,如果插入数据量大于当前容器所有的数据总量的时候,那么增加的容量大小为待插入数据的总量。
      resize在开辟空间的同时还会进行初始化,影响size

void test04()
{
    vector<int> v;
    //v.reserve(100000);

    int *p = NULL;
    int num = 0;
    for(int i = 0; i < 100000; i++)
    {
        v.push_back(i);
        if(p != &v[0])
        {
            p = &v[0];
            cout << v.capacity() << endl;
            num++;
        }
    }
    cout << num << endl;
    // 开辟100000数据用了多少次
}

数据存取操作

函数名称函数功能
at(int idx)返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
operator[]返回索引idx所指的数据,越界时,运行直接报错
front()返回容器中第一个数据元素
back()返回容器中最后一个数据元素
void test08()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	for(auto x : v)
	{
	    cout << x << " ";
	}
	cout << endl;
}

增删改查

函数名称函数功能
void push_back(const value_type &val)尾插
void pop_back()尾删(并不会改变容量)
iterator insert(iterator position, const value_type &val)在position之前插入val
iterator erase(iterator postion)删除position位置的数据,不改变底层容量
void clear()清空vector,但不改变底层容量

迭代器失效的情况

void test09()
{
    int a[] = {1,2,3,4};
    vector<int> v(a, a + sizeof(a) / sizeof(a[0]));
    
    // 使用find查找3所在位置的iterator
    vector<int>::iterator pos = find(v.begin(), v.end(), 3);

    // 删除pos位置的数据,导致pos迭代器失效
    v.erase(pos);
    cout << *pos << endl;//此处会导致非法访问
    
    // 在pos之前插入数据,可能会导致迭代器失效
    // 因为insert可能会导致扩容
    pos = find(v.begin(), v.end(), 3);
    v.insert(pos, 30);
    cout << *pos << endl;
}

void test10()
{
    int a[] = {1,2,3,4};
    vector<int> v(a, a + sizeof(a) / sizeof(a[0]));

    // 实现删除v中所有偶数
    // 如果是偶数,erase将会导致it失效
    // 对于失效的it进行++,会导致程序崩溃
    
    vector<int>::iterator it = v.begin();
	# if 0
    while(it != v.end())
    {
        if(*it % 2 == 0)
        {
            v.erase(it);
        }  
        ++it;
    }
   #endif
    while(it != v.end())
    {
        if(*it % 2 == 0)
        {
            it = v.erase(it);
        }
        else
        {
            ++it;
        }
    }
    for(auto x : v)
    {
        cout << x << endl;
    }
}
如果你在使用c++11的新特性的话,一定要加上-std=c++11选项
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值