「STL::vector」标准库容器:vector(动态数组|向量)介绍(C++)

目录

概述

构造析构

赋值重构 

数据访问

迭代器

内存管理

数据控制

Tips


概述

vector 是一种C++标准模板库STL中定义的一种序列容器,它允许你在运行时动态地插入和删除元素。

vector 是基于数组的数据结构,但它可以自动管理内存,这意味着你可以添加任意多的元素在其中,并且你不需要手动分配和释放内存。

它同时具有动态类型和数组的特性:

动态大小:内存空间可以根据需要自动增长和缩小。

连续存储:元素在内存中是连续存储的,这使得访问元素非常快速。

可迭代:可以被迭代,你可以使用循环来访问它的元素。

元素容器:可以存储任何类型的元素,包括基本类型、对象、指针等。

接下来,我们介绍vector类型定义的成员函数。

*注意*:本文不涉及allocator空间配置器和C++23新增的range类函数。

创建销毁

STL库提供了以下方式创建一个vector。

T表示任意类型。

无参构造

vector<T>vec();

生成一个存储T类型的动态数组vector。

提供初始空间的构造

vector<T>vec(int num);

生成初始长度为num的vector,初值为0。

提供初始长度和初值的构造

vector<T>vec(int num,T target);

生成初始长度为num的vector,初值为target。

提供源数据地址的构造

vector<T>vec(T* begin,T* end)

从定长数组(初末指针)或另一容器(初末迭代器)中获取数据进行构造。

需要注意的是,迭代器指向的容器不一定是另一个vector,它只需是一个提供随机访问迭代器(即支持it++、it--)的容器即可。

拷贝构造

vector<T>vec(const vector& another);

将another整体赋值给新vector。

移动构造

(C++11)

vector<T>vec(vector&& another);

窃取另一个vector容器,即直接获取它维护的底层指针地址,再将它的指针置空。

初始化列表构造(C++11)

vector<T>vec(std::initializer_list<T> ini_list);

为了让vector模仿int a[]={1,2,3},C++11提供了这种构造。initializer_list(初始化列表)是由C++11提供的类型,使用{}进行初始化。

vector<int>vec={1,2,3};隐式构造了一张无名initializer_list,然后它被作为参数传入vec的初始化构造中

析构函数

~vector();

无须手动调用。程序自动在代码块结束时调用,清理掉vector。

vector<int>a;//{}无参构造
vector<int>b(3); //{0,0,0,}//提供初始长度
vector<int>c(3,5);//{5,5,5,}//提供初始长度和初始值
int x[] = {1,2,3,4,5,6};
vector<int>d(x,x+6);//{1,2,3,4,5,6,}//提供源地址
vector<int>e(d);//{1,2,3,4,5,6,}//拷贝构造
vector<int>f={9,8,7,6,5};//{9,8,7,6,5}//初始化列表构造

赋值重构

在必要时我们会对vector进行重新初始化。

重载拷贝赋值=

vector& (const vector& another);

作用同拷贝构造。不仅可以在初始构造时使用。返回自身。

重载移动赋值=

vector& (vector&& another);

作用同移动构造。不仅可以在初始构造时使用。返回自身。

再分配

void assign();

参数列表与提供初始长度和初值的构造;提供源数据地址的构造;初始化列表构造相同。

功能同对应构造函数。仅能在已存在的vector上使用。

数据访问

 vector同时提供了类形式的函数访问和数组形式的运算符访问

重载[]号访问

operator[](int pos);

模仿定长数组的数据访问形式,如arr[3]=5;

vector因此使用起来与定长数组无异。

成员函数式访问

at(int pos);

返回pos处元素的引用。它与[]号相同,除了越界。(使用[]造成越界会直接崩溃,用at则会抛异常,可以用try catch捕获)

访问头元素

front();

返回头元素。

访问尾元素

back();

返回尾元素。

直接访问底部

data();

返回vector维护的底部数组的头地址。

(vector是基于数组这种数据类型的容器,它的所有操作都是在维护他的成员指针指向的定长数组)

//d的内部:{1,2,3,4,5,6,}
d.at(2) = 7;
d.front() = 9;
d.back() = 8;
for (int i = 0; i < 6; i++)cout << d[i];//输出927458
int* p = d.data();//p得到了头元素d[0]的地址
cout << *p;//输出9

迭代器

迭代器是c++STL库提供的指向容器的类型,有着类似指针的作用。

通常定义vector<T>::iterator it=.....来获得一个指向某处的it迭代器。

头位置

begin();

返回头位置(vector第一个元素的位置,vector为空时和end相等)。

尾位置

end();

返回尾位置。(它指向的位置是第一个不属于vector的位置而不是vector的最后一个元素。)

常量头位置

(C++11)

cbegin();

返回头位置,赋值给const_iterator类型。这种迭代器不可修改容器。

常量尾位置

(C++11)

cend();

返回常量尾位置。

逆序头位置

rbegin();

返回逆序头位置,赋值给reverse_iterator类型。指向最后一个元素(与end不同),对逆序迭代器的++操作会使其向头部移动,--向尾部移动(与正序相反)

逆序尾位置

rend();

返回逆序尾位置,指向vector前面的那个不属于vector的位置(与front不同)

常量逆序头位置

(C++11)

crbegin();

返回常量逆序头位置,赋值给const_reverse_iterator类型。

常量逆序尾位置

(C++11)

crend();

返回常量逆序尾位置。

//d的内部:{1,2,3,4,5,6,}
for (vector<int>::const_iterator cit = d.begin(); cit != d.end(); cit++)
cout << *cit;
//输出123456

for (vector<int>::const_reverse_iterator crit = d.crbegin(); crit != d.crend(); crit++)
cout << *crit;
//输出654321

内存管理

vector不仅可以自动管理内部空间,还支持程序员手动管理内部空间

vector内部关于内存同时拥有size和capacity两种参数,为什么?

试想:每次申请长度都只是当前长度+1,则会在内存空间中反复向后利用函数申请新空间来维护数据,这同时耗费了时间和空间。

那么如果每次都申请真实长度size的两倍空间capacity,则每次申请后都有一段空闲区域容纳新元素,此时不需要申请新空间,只有当再次填满时才申请新空间,则减少了时间成本,提高了空间利用率。

获取实际长度

size();

返回vector中的有效元素个数。

控制实际长度

resize(int num);

resize(int num,T target);

将有效元素限制到num个。size>num时抛弃多余部分;num>size则将将多出的位置置为target,无target时置为0.

获取真实空间大小

capacity();

获取vector维护的底层数组的全部容量。

控制真实空间

reserve(int num);

num>capacity时扩容,否则无事发生。

判断是否为空

empty();

size==0时返回true,否则返回false。

空间收缩

shrink_to_fit();

将capacity收缩至size大小。

获取整个程序的极限容纳空间

max_size();

返回整个程序支持的理论最大vector长度。

数据控制

vector类型通过成员函数维护数据。

iterator即为上文的迭代器。

尾部压入

push_back(T elem);

在尾部加入元素。

尾部弹出

pop_back();

删除尾部最后一个元素。

插入

insert(vector<T>::iterator it,T elem);

insert(vector<T>::iterator it,T* begin,T*end);

在迭代器it(后文提及)指向的位置加入元素,原元素依次向后移动。

在it指向的位置加入多个元素,源地址为begin到end。源地址的类型不局限于定长数组和vector,只需是一个包含T类型的完整范围。

删除

erase(vector<T>::iterator it);

erase(vector<T>::iterator it1,vector<T>::iterator it2)

删除it指向的元素。

删除it1到it2之间的元素,满足左闭右开原则(it1位置被删除,it2不删除)

交换

swap(vector& another);

交换两个容器的元素。

清空

clear();

清空元素。

尾部安置(C++11)

emplace_back(T elem);

C++11后可用,在尾部原地构造一个元素,作用与push_back()相同,但没有赋值过程而是原地生成新元素,所以效率更高。

头部安置(C++11)

emplace_front(T elem);

与empalce_back()类似。

插入安置(C++11)

emplace(vector<T>::iterator it,T elem);

emplace(vector<T>::iterator it,T* begin,T*end);

作用于insert相同,但因为上述原因效率更高。

Tips

vector<bool>不是装载bool类型的标准vector容器,这个奇异搞笑的类型不是vector<T>的一个实现,它就叫"vector<bool>",常年被c++标准委员会诟病。它本来是用来演示如何使用STL库的一个小白鼠,存储bool这个bit大小的元素,在一个字节上存了八个。它的运行效率极低,不推荐使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值