从零开始的C++生活——第六讲——01

第五讲我们讲了string,这一讲开始,我要引入一个新的stl容器,vector也就类似于数据结构的顺序表。

首先讲一下vector的构造方法。

从上到下,分别对应默认构造、用n个字符填充数组的构造、利用迭代器构造、以及拷贝构造,我先讲前三个传统的构造。

cpp 复制代码
void test_vector_init()
{
	//默认构造
	vector<int> v;
	//n个元素构造
	vector<int> v1(10, 8);
	//迭代器构造
	vector<int> v2(++(v1.begin()), --(v1.end()));

}

从字面意思就很好理解这三个构造方法,但是从中我们可以提取到一些关键信息,首先,vector的成员变量主要是数组+capacity+size三个,这三个成员变量可以维护数组的大部分信息。

此外,vector也支持迭代器,我接下来讲一讲迭代器以及遍历。

和string区别并不大,vector的迭代器种类也是这四组,分别是begin/rbegin/cbegin/crbegin。我这里就begin/end做一个演示。

cpp 复制代码
for (int i = 0; i < v1.size(); i++)
{
	cout << v1[i] << " ";
}
cout << endl;

vector<int>::iterator it1 = v1.begin();
while (it1 != v1.end())
{
	cout << *it1 << " ";
	it1++;
}
cout << endl;
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;

结合三组遍历方式,首先我们可以发现iterator在vector中的使用和string基本是没区别的,此外,上述代码传递了些许信息,首先,我没用cout<<v1直接对数组进行打印,因为vector并没有重载<<,>>两个流操作符,此外我使用了\[\]访问数组元素,也进而说明vector重载了\[\]操作符。

接下来是这一组

size不必多说,返回当前数组元素个数,capacity也类似,返回当前数组空间大小,empty返回当前数组是否为空。

其中比较需要讲解的是resize和reserve

vector中的reserve和string中的略有不同

这段话是说,当你给reserve传一个大于当前容量的值时,会对数组进行扩容,除此之外不会对空间有任何影响。

和string中的reserve不同的是,string对于n小于capacity的情况是不做要求的,虽然在vs中并没有实现缩容,但不代表不可以这么做,但vector就已经限定死了。

此外reserve不会对原来元素进行修改。

cpp 复制代码
void test_vector_reserve()
{
	vector<int> v(10, 8);
	cout << v.capacity() << endl;
	cout << v.size() << endl;

	v.reserve(20);
	cout << v.capacity() << endl;
	cout << v.size() << endl;

	v.reserve(15);
	cout << v.capacity() << endl;
	cout << v.size() << endl;

	v.reserve(5);
	cout << v.capacity() << endl;
	cout << v.size() << endl;
}

接下来是resize

和string使用方法别无二致,规则也没什么区别,这里不做讲解,详情请参考上一讲。

cpp 复制代码
void test_vector_resize()
{
	vector<int> v(10, 8);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << v.capacity() << endl;
	cout << v.size() << endl;

	v.reserve(20);
	cout << v.capacity() << endl;
	cout << v.size() << endl;

	v.resize(15, 9);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << v.capacity() << endl;
	cout << v.size() << endl;

	v.resize(5);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << v.capacity() << endl;
	cout << v.size() << endl;

}

接下来,我对vector的插入做一个讲解

插入主要用的是push_back和insert,我先讲一下push_back尾插

push_back尾插需要注意的是,只能尾插一个元素,如果空间不够数组会自行扩容。

cpp 复制代码
void test_vector_push_back()
{
	vector<int> v(10, 8);
	v.reserve(20);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << v.capacity() << endl;
	cout << v.size() << endl;
	for (int i = 0; i < 20; i++)
	{
		v.push_back(i);
		/*cout << v.capacity() << endl;
		cout << v.size() << endl;*/
	}
	for (auto e : v)
	{
		cout << e << " ";

	}
	cout << endl;
	cout << v.capacity() << endl;
	cout << v.size() << endl;
}

vector的扩容逻辑和string类似,也是1.5倍扩容。

接下来讲一下insert

和string不同的一点是,vector中的insert不再支持下标传参,只能传迭代器。

cpp 复制代码
void test_vector_push_back()
{
	vector<int> v(10, 8);
	v.reserve(20);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << v.capacity() << endl;
	cout << v.size() << endl;
	for (int i = 0; i < 20; i++)
	{
		v.push_back(i);
		/*cout << v.capacity() << endl;
		cout << v.size() << endl;*/
	}
	for (auto e : v)
	{
		cout << e << " ";

	}
	cout << endl;
	cout << v.capacity() << endl;
	cout << v.size() << endl;
}
void test_vector_insert()
{
	vector<int> v(10, 8);
	vector<int>::iterator it = v.begin();
	v.insert(it, 100);
	for (auto e : v)
	{
		cout << e << " ";

	}
	cout << endl;
	it = v.begin();
	v.insert(it + 3, 4, 99);
	for (auto e : v)
	{
		cout << e << " ";

	}
	cout << endl;
	vector<int> v1(6, 6);
	it = v.begin();
	v.insert(it + 1, v1.begin() + 1, v1.begin() + 4);
	for (auto e : v)
	{
		cout << e << " ";

	}
	cout << endl;

	string s1("aaaaaaa");
	it = v.begin();
	v.insert(it + 1, s1.begin() + 1, s1.begin() + 4);
	for (auto e : v)
	{
		cout << e << " ";

	}
	cout << endl;
}

有几点需要注意,首先,当你扩容后需要重新指定迭代器,不然指向的还是原先空间,其次string类也可以利用第三种插入方式插入到vector中,只不过是ASCII码值。

本质insert还是挪动数组,所以谨慎使用,保不齐会影响效率。

最后,我讲一下关于vector的模板参数,首先类模板需要显式实例化。

其次vector的模板参数可以是vector也可以是string等自定义类型

cpp 复制代码
void test_vector_p()
{
	vector<string> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back("hello world");
	}
	for (auto e : v)
	{
		cout << e << " ";
		cout << endl;
	}
	cout << endl;

	vector<vector<int>> v1;
	for (int i = 0; i < 5; i++)
	{
		vector<int> v2(i + 1, i);
		v1.push_back(v2);
	}
	for (auto e : v1)
	{
		for (auto k : e)
		{
			cout << k << " ";
		}
		cout << endl;
	}
	cout << endl;
	cout << v1[2][2] << endl;
}

有点像二维数组。

关于vector的使用我就先讲到这,后续还会接着补充。

相关推荐
淡漠的蓝精灵1 小时前
web.py:一个简单到极致的 Python Web 框架
开发语言·前端·python·其他
乌暮2 小时前
请求进门先安检:Spring 拦截器与统一功能实战指南
java·开发语言·后端·学习·spring
এ慕ོ冬℘゜2 小时前
JS 事件循环、宏任务微任务:单线程底层原理 + 执行顺序
开发语言·javascript·ecmascript
其实防守也摸鱼2 小时前
Chrome 扩展安全攻防实录:从攻击面到防御实践
开发语言·前端·网络·chrome·安全·web安全·php
web打印社区2 小时前
Lodop排障总纲-常见报错一张表
开发语言·前端·javascript·chrome·websocket
Risehuxyc3 小时前
C++(VS2026)使用Ncap库的配置
c++
Dxy12393102163 小时前
JS AES加密详解
开发语言·javascript·ecmascript
信息安全失业大专人员3 小时前
每日了解一个智能体-WorkBuddy
开发语言·ai·c#·智能体
4ever.ov04 小时前
精学C++第一站 从命名空间到引用:C++入门核心语法全梳理(13000字长文)
开发语言·c++·clion