STL容器用法与介绍之vector

1. 特点

a) vector是一个封装了动态大小数组的顺序容器,并支持反转;

b) vector是在堆上分配内存,并在内存中具有连续的存储空间,它提供了自动内存管理功能,随着元素的增加或删除,内存会同步进行增大或缩小;

c) 访问vector中的元素可以通过元素下标实现随机访问,也可以通过迭代器实现顺序访问;

d) 在vector尾部添加和删除元素的时间复杂度是O(1),但是在vector头部或中间插入和删除元素的时间复杂度是O(N)。原因:由于vector的内存空间是连续的,所以在头部和中间进行插入和删除会造成内存块的拷贝。如果vector内存空间不够时,还需要重新申请一块足够大的内存再进行内存拷贝。如果vector中的元素是结构体或者类,对头部和中间的元素进行插入删除不仅需要拷贝内存块,还会进行析构和构造操作。

2. 优缺点及使用场景

优点:支持随机储存,查询效率高;

缺点:在头部和中间插入删除元素需要移动内存,效率低;

使用场景:适用于元素结构简单,变化小,并且频繁随机访问但不需要对头部和中间元素进行添加删除操作的场景。

3. 基本操作

a) 创建对象与初始化

std::vector<T> vecTest1; //vecTest1是一个空的vector,它潜在元素类型为T
std::vector<T> vecTest2(vecTest1); //vecTest2中包含有vecTest1中所有元素的副本
std::vector<T> vecTest2 = vecTest1; //与上式等价
std::vector<T> vecTest3(n, val); //vecTest3中包含了n个重复的元素,每个元素的值都是val

//以下为C++11新特性,使用之前请确认编译器是否支持
std::vector<T> vecTest4{a, b, c...}; //vecTest4包含了初始值个数的元素,每个元素被赋予相应的初始值
std::vector<T> vecTest4 = {a, b, c...}; //与上式等价

b) 增加元素

std::vector<int> vecTest1 = {1, 2, 3, 4, 5};
std::vector<int> vecTest2 = {6, 7, 8, 9, 10};
vecTest1.push_back(6); //在vector尾部增加一个元素6
vecTest1.insert(vecTest1.begin(), 6); //在vector头部增加一个元素6
vecTest1.insert(vecTest1.end(), 5, 6); //在vector尾部增加5个相同的元素6
vecTest1.insert(vecTest1.begin(), vecTest2.begin(), vecTest2.end()); //在vecTest1的头部插入vecTest2[first, last)间的元素
vecTest1.emplace_back(6); //在vector尾部增加一个元素6

push_back/insert/emplace_back之间的区别:

push_back把元素插入容器的末尾,insert把元素插入任何指定的位置。不过push_back速度一般比insert快。如果能用push_back尽量先用push_back。emplace_back是在C++11标准中引入的。它的用法与完成的动作与push_back完全相同,但它们的实现不一样。使用push_back时,首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数,将这个临时对象放入容器中,最后将这个临时变量释放;使用emplace_back时,因为输入的是元素引用,只需要在添加元素的时候构造一次即可,不需要触发拷贝构造和转移构造。

c) 删除元素

std:vector<int> vecTest2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
vecTest1.erase(vecTest1.begin() + 2); //删除第3个元素
vecTest1.erase(vecTest1.begin() + i, vecTest1.begin() + j); //删除区间[i, j - 1]之间的元素
vecTest1.pop_back(); //删除vector尾部的元素,使用之前需要进行非空判断
vecTest1.clear(); //清空所有元素

d) 访问元素

std::vector<int> vecTest1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int iValue1 = vecTest1[0]; //返回下标为0的元素引用
int iValue2 = vecTest1.at(0); //与上式相同,如果下标不存在,会抛出out_of_range的异常,建议使用
int iValue3 = vecTest1.front(); //返回vector头部元素的引用,使用前需要进行非空判断
int iValue4 = vecTest1.back(); //返回vector尾部元素的引用,使用前需要进行非空判断
for (std::vector<int>::iterator iter = vecTest1.begin(); iter != vecTest1.end(); ++iter)
{
    int iValue = *iter;
}

e) 替换元素

std::vector<int> vecTest1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> vecTest2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
vecTest1.assign({1, 2, 3, 4}); //相当于赋值操作,C++11新特性,使用之前请确认编译器是否支持
vecTest1.assign(5, 3); //与上式类似,用5个3对vecTest1进行赋值
vecTest1.assign(vecTest2.begin(), vecTest2.begin() + i); //使用vecTest2中[0, i - 1]区间的元素对vecTest1进行赋值
vecTest1.swap(vecTest2); //交换vecTest1和vecTest2中的元素

f) 元素反转

//需要头文件#include<algorithm>
std::reverse(vecTest1.begin(), vecTest1.end());

g) 元素排序

//需要头文件#include<algorithm>
std::sort(vecTest1.begin(), vecTest1.end()); //默认按升序排列

bool Comp(const int& a, const int& b) //自定义排序比较函数
{
    return a > b;
}
std::sort(vecTest1.begin(), vecTest1.end(), Comp); //按自定义排序比较函数降序排列

h) 元素唯一

//需要头文件#include<algorithm>
//结合使用std::sort/std::unique/erase
std::vector<int> vecTest1 = {1, 3, 3, 5, 4, 5, 3, 7, 9};
std::sort(vecTest1.begin(), vecTest1.end());
vecTest1.erase(std::unique(vecTest1.begin(), vecTest1.end()), vecTest1.end());

i) 元素与指针结合使用

我们有时候会用智能指针来表示二级指针(指向指针的指针),实现指针的自动管理,防止内存泄漏。

int** ptr = new int*[iSize];
for (int i = 0; i < iSize; ++i)
{
    ptr[i] = new int[iSize];
}


std::vector<std::unique_ptr<int[]>> vecSubTest; //增加智能指针的引用计数,防止智能指针提前释放
std::unique_ptr<int*[]> upTest(new int*[iSize]);
for (int i = 0; i < iSize; ++i)
{
    std::unique_ptr<int[]> upSubTest(new int[iSize]);
    vecSubTest.push_back(std::move(upSubTest));
    upTest[i] = vecSubTest[i].get();
}

在上例中ptr是和upTest.get()是等价的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值