C/C++笔记总结——vector容器

一、基本概念

        vector数据结构和数组非常相似,也称为单端数组。与普通数组的区别在于数组是静态空间,而vector可以动态扩展。并不是在原空间之后续接新空间,而是找到一块更大的内存空间,将原数据拷贝到新空间,释放原空间。因为它以数组的形式储存,所以它的内存空间是连续的

        vector容器可以进行尾插,插入,遍历,头删,尾删等操作,用图表示如下:

        注意,vector不能进行头插,即不能直接对头端元素进行操作,这也是 vector 容器和 deque 容器最重要的区别之一。

 二、基本操作

2.1 构造函数

构造函数
函数原型实现功能
vector<T> v创建一个vector对象,默认构造函数
vector(v.begin(),v.end())将v[begin(),end())区间中的元素拷贝给本身,左闭右开
vector(n,elem)构造函数将n个elem拷贝给本身
vector(const vector &vec)拷贝构造函数

举例代码:

vector<int>v1;
for (int i = 0; i < 10; i++) {
	v1.push_back(i);
}

//用区间的方式构造
vector<int>v2(v1.begin(), v1.end());

//n个值构造
vector<int>v3(10, 5);	//10个5

//拷贝构造
vector<int>v4(v3);

2.2 容量和大小

容量和大小
函数原型实现功能
capacity()得到vector对象的容量
size()得到vector对象的大小
resize()重新指定大小

举例代码:

vector<int>v1;
for (int i = 0; i < 10; i++) {
	v1.push_back(i);
}
cout << "v1的容量为:" << v1.capacity() << endl;		//13
cout << "v1的大小为:" << v1.size() << endl;			//10

//重新指定大小
v1.resize(15);          //后面会补5个0
v1.resize(15, 100);		//后面会补5个100

2.3 插入和删除

插入和删除
函数原型实现功能注意事项
push_back(a)在尾部插入一个元素a
insert(a.begin+i,k)在下标为i的元素前插入k第一个参数是迭代器
insert(a.end(),n,m)在末尾插入n个值为m的元素第一个参数是迭代器
insert(a.end,{1,2})在末尾插入值“1,2”第一个参数是迭代器
pop_back()删除末尾元素容器大小(size)会减一,容量不变
erase(a.begin()+i,a.begin()+j)

将[i,j-1]的元素都删除

两个参数都是迭代器
erase(a.begin()+i)

将[i,j-1]的元素都删除

参数是迭代器
remove()

删除容器中所有和指定元素相等的元素,并返回指向最后一个元素下一个位置的迭代器

clear()清空数组

先看举例代码,然后再解释什么是迭代器,迭代器又有什么用。(该示例代码可以运行

#include<iostream>
#include<string>
using namespace std;
#include<vector>

void printVector(vector<int>& v) {
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void text01() {
	vector<int>v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i);	//尾插法
	}
	//尾删
	v1.pop_back();
	printVector(v1);
	//插入
	v1.insert(v1.begin(), 100);		//在开头插入一个100,第一个参数是一个迭代器
	printVector(v1);
	v1.insert(v1.begin(), 5, 100);	//在开头插入5个100
	printVector(v1);
	//删除
	v1.erase(v1.begin()+8);		//删除下标为8的元素
	printVector(v1);
	//清空
	v1.clear();
	printVector(v1);
}
int main() {
	text01();
}

2.4 迭代器(iterator)

        然后我们来解释迭代器(iterator),这里只需要清楚迭代器在不同的函数中的作用是什么就可以了,更详细的了解比较费力,就先不作解释。

        如上例,我们实现了插入和删除操作,但是你可能会想,我们做的操作都是在开头或末尾进行插入或删除,即使删除“下标为8的元素”,也是用 v1.erase(v1.begin()+8) 实现。如果我们采用如下做法:

v1.insert(0, 100);

        看似是在“下标为0的元素前插入一个元素 100”,好像没什么差别,但是编译器会报错。那么有两个疑问就油然而生:为什么一定要用 v1.begin() 和 v1.end()?如果我无法确定插入位置和起始位置的距离(即无法确定 i )时该怎么办?

        第一个问题先不做解释,大多数情况下我们只需要知道怎么灵活使用即可。

        我们可以定义一个 vector<int> 类型的迭代器 it,然后对 it 进行操作,修改 it 的值,让它指向我们想指向的位置,可以用 it 代替 v1.begin()+i 。具体代码如下:

vector<int>::iterator it = v1.begin();
it++;                //可以对it操作,修改it的值
v1.insert(it,5);     //在下标为it的元素前插入5

        此法在其他容器(如deque容器)对应操作也同样适用。

2.5 其他常用函数

函数原型实现功能
front()返回容器中第一个数据元素
back()返回容器中最后一个数据元素
swap(vector)将vector与本身的元素互换

2.5.1举例代码

可运行

#include<iostream>
#include<string>
using namespace std;
#include<vector>

void printVector(vector<int>& v) {
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void text01() {
	vector<int>v1;
	vector<int>v2;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i);
	}
	for (int i = 10; i > 0; i--) {
		v2.push_back(i);
	}
	v1.swap(v2);
	printVector(v1);
	printVector(v2);
}

int main() {
	text01();
	return 0;
}

2.5.2 swap实际应用(收缩内存)

void text02(){
	vector<int>v;
	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
	}
	cout << "v的容量为:" << v.capacity() << endl;        //138255
	cout << "v的大小为:" << v.size() << endl;            //100000

	v.resize(100);		        //为v重新指定大小
	cout << "v的容量为:" << v.capacity() << endl;        //138255
	cout << "v的大小为:" << v.size() << endl;            100

	vector<int>(v).swap(v);		//收缩内存,匿名对象
	cout << "v的容量为:" << v.capacity() << endl;        //100
	cout << "v的大小为:" << v.size() << endl;            //100
}

        v刚开始容量为138255,大小为100000;当重新指定大小之后,容量没变,大小变为100,那么剩余的空间就全都浪费掉了(占用内存但并未存储数据);当使用swap收缩内存后,v的大小和容量都改变了,就避免了空间浪费。

解释swap代码:

        vector<int>v  是个匿名对象,相当于创建了一个新的对象,暂且看做x;

        x会按照当前v所用的内存大小来初始化,比如现在v的大小为100,就初始化x的大小为100,容量也是100;

        之后又“swap”相当于交换了x和v,交换后x指向容量为138255的内存空间,v指向容量和大小为100的内存空间;

        x由于是匿名对象,所以当39行代码执行完毕后,编译器会回收该代码,即不用担心x过多占用空间。

2.6 预留空间

函数原型实现功能
reserve(a)预留出a的长度大小的空间

        由于vector是一个动态数组,所以当我们插入元素过多时,会不断地扩展内存,更新容量,这是非常耗费时间的。我们举例说明:

#include<iostream>
#include<string>
using namespace std;
#include<vector>

void text01() {
	vector<int>v;
	int num = 0;	//统计开辟空间的次数
	int* p = NULL;	//指针指向v的首元素地址
	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
		if (p != &v[0]) {	//如果p不指向首元素地址,就代表开辟了新的空间
			p = &v[0];
			num++;
		}
	}
	cout << "num=" << num << endl;
}

int main() {
	text01();
	return 0;
}

        上例我们插入100000次数据,得到 num = 30 ,即扩展了30次内存,太耗费时间。我们可以使用 reserve 预留空间,这将大大提高代码的运行效率。添加进去后,完整代码如下:

#include<iostream>
#include<string>
using namespace std;
#include<vector>

void text01() {
	vector<int>v;

	v.reserve(100000);        //预留空间

	int num = 0;	//统计开辟空间的次数
	int* p = NULL;	//指针指向v的首元素地址
	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
		if (p != &v[0]) {	//如果p不指向首元素地址,就代表开辟了新的空间
			p = &v[0];
			num++;
		}
	}
	cout << "num=" << num << endl;
}

int main() {
	text01();
	return 0;
}

        这次我们计算得 num = 1 ,只扩展了一次内存,大大缩短了程序执行时间。

        注意:预留位置不初始化,元素不可访问。

        以上就是我对 vector 容器的总结,希望对您有所帮助。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值