常用容器之二—— vector 和 list 。
目录
vector(向量):
vector是一个能够存放任意类型的动态数组,只能在尾部进行插入和删除,其实它的用法和数组一样,只是它的功能比数组强大。
优点:
1.可以随机访问任意一个元素。(和数组一样)
2.它是动态数组,动态数组是当内存不够的时候,它可以自动扩增,而不需要我们人为地进行扩增。
缺点:
和数组一样,不能很好的进行插入和删除操作。
必须加头文件 #include<vector>
先简单介绍一下函数 push()、empty()、pop()、size()、capacity()、max_size()。
push_back(); //在向量尾部增加一个元素
empty(); //判断向量是否为空
pop_back(); //删除向量中最后一个元素
size(); //返回向量中元素的个数
resize(); //设置大小(调整容器的长度)
capacity(); //返回当前向量的容量
max_size(); //返回可允许的元素数量的最大值
其实这些函数的用法与之前我们所学的string和stack、queue里面的用法是一样的 ,特别是capacity()和resize()函数。
具体请参照之前 string 的博客。
reserve(); //设置容量(调整容器的容量大小)
在这里主要区分一下 resize() 和 reserve() 函数。
1. resize(n)函数:
resize(n):调整容器的长度大小,使其能容纳n个元素
如果n小于当前的size,则删除多出来的元素,反之,不够的用值初始化元素的默认值来填充。
resize(n,t):这是对于n大于当前的size的情况时,就将新增加的元素都初始化为t(即用t来填充)。
2. reserve(n)函数:
reserve(n):预分配n个元素的存储空间。
如果n小于或者等于capacity,其容量就不会变,反之,就重新分配内存空间,从而使capacity=n。
简单点说,就是 resize()函数与容器的size有关,而reserve()函数与容器的capacity有关。
区别:
调用resize()函数后,所有的空间都已经初始化了,所以可以直接访问;而reserve()函数预分配出的空间没有被初始化,所以不可访问。
可以看到,最开始增加元素数量为10时,而此时容量16比10大,这是因为计算机认为你可能还要再增加元素,所以就多开辟了一些空间。
另外还有一些函数,front()、back()。
front(); //返回首元素
back(); //返回尾元素
以上函数就不再细说了,在下面的代码中都会经常用到。
初始化
//Vector<类型>标识符
vector<int>v; //创建一个空的 vector
//Vector<类型>标识符(最大容量)
vector(int n); //创建一个元素个数为 n 的vector
以上两种最好还是用第二种形式。
原因:
可以看到,随着元素个数的增加,容量也由0变为了1,而我们前面学string的时候就学习过容量capacity()函数的特性,当元素个数超过了容量之后,此时我们就需要创建一个更大容量的数组,然后把数据复制到这个新数组中,这样会大大降低效率,所以我们尽量不这样做,相比之下,所以我们还是尽量采取以下形式:(提前为其分配空间 )
//Vector<类型>标识符(最大容量,初始值)
vector(int n,const t) //创建一个 vector,元素个数为n,且值均为t
//Vector<类型>标识符(begin,begin+n)
vector<类型>v1(); //先构造容器v1
vector<类型>v(v1.begin(),v1.begin()+n); //用v1将v初始化
这样也可以:
用数组对容器进行初始化
总之是可以这样用的,至于其中的道理,我是这样来理解记忆的(虽然不一定理解对了,但最起码能帮助记住):
以上就是初始化的方法。
访问
直接使用中括号来访问 //与数组用法一样
对了,要是想让它们都输出在第一行,就这样写就好了:
at();
区别:中括号与at()函数的区别就在于at()能检测是否越界,具体的我们在学string时都有详细了解过,如果还不明白的话可以去看一下之前的string的博客。
赋值
插入
insert();
删除
erase();
清空
clear();
收缩内存
swap();
可以看到,当我们使用swap来收缩内存的时候,其容量也确实随之变了。
list(双向链表):
优点:
1. 与向量(vector)相比,它可以快速的进行插入和删除操作。
2. 不使用连续的内存空间就可以随意的进行动态操作。
缺点:
1. 由于它是链表,所以它随机访问比较慢,相比vector不能使用at()来访问。
2. 相对于 vector 占用了更多的内存。
必须加头文件 #include<list> 。
初始化
它的初始化与向量(vector)的初始化方法基本上是一样的(也是上面那5种方法)。
基本函数
它的基本函数与上面向量(vector)的大同小异,可以参照上面的。
还有函数:
begin(); //返回指向第一个元素的迭(die)代器
end(); //返回末尾的迭(die)代器
下面来列举一下不同于以上的函数:
赋值
list assign(); //给list赋值
也可以这样:
当然链表list同以上vector一样也可以直接将一个链表赋值给另一个链表,如下:
合并
merge();
删除
remove();
倒转(逆序)
reverse(); //将链表list中的元素倒转
排序
sort();
交换
swap();
删除重复元素
unique(); //删除list中重复的元素
以上是两个比较常用的容器vector和list的相关函数以及用法的总结,其实可以把它们两个看成正好相反的两个,也是比较有意思的哈哈。