STL中容器vector -- 讲解超详细 - 详解

序言

在上一节已经学习了string的接口和模拟实现,vector的接口和string大差不差,重点是vector的模拟实现和迭代器失效的问题!!!

这是vector的一些常用的接口,下面分别来讲解:

1. vector常见的构造函数

无参构造vector()
传值构造vector(size_t n, const value_type& val = value_type())
拷贝构造vector(const vector& x)
迭代器构造vector(iterator first,iterator last)
初始化列表构造vector(initializer_list()<value_type> it)
void test01()
{
	// 无参构造
	vector v1;
	// 传值构造
	vector v2(10, 1); // 初始化为10个1
	vector v3(10); // 初始化为10个0(初始化的值由编译器决定)
	// 初始化列表构造
	vector v4({ 1,2,3,4,5,6,7,8,9,10 });
	// 迭代器构造
	vector v5(v4.begin() + 5, v4.end());
	vector::iterator it = v5.begin();
	while (it != v5.end())
	{
		cout << (*it) << " ";
		it++;
	}
	cout << endl;
}

2.  vector的增删查改

2.1 尾插和尾删

    void push_back(const value_type & val);
   void push_back(value_type && val);
void pop_back();
void test02()
{
    // 尾插
	vector v1;
	v1.push_back(1);
	v1.push_back(9);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(1);
	for (auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
    // 尾删
    v1.pop_back();
    v1.pop_back();
	for (auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

2.2 任意位置插入和删除

2.2.1 insert

表中是insert常见的接口:

指定位置插入valiterator insert (const_iterator position, const value_type& val);
指定位置插入范围数据iterator insert (const_iterator position, iterator first, iterator last);
指定位置插入初始化列表iterator insert (const_iterator position, initializer_list<value_type> il);

常见接口的使用:

void test03()
{
	vector v1({ 1,2,3,4,5,6,7,8,9,10 });
	// 指定位置插入val
	v1.insert(v1.begin() + 3, 9);
	v1.insert(v1.begin() + 6, 12);
	for (auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	// 指定位置插入范围数据
	vector v2 = { 136,232,888 };
	v1.insert(v1.end(), v2.begin(), v2.end());
	for (auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	// 指定位置插入初始化列表
	v1.insert(v1.begin(), { 99,66,55,77,88 });
	for (auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

2.2.2 erase

表中是erase常见的接口:

删除指定位置元素iterator erase (const_iterator position);
删除迭代区间元素iterator erase (const_iterator first, const_iterator last);

常见接口的使用:

void test04()
{
	// 删除指定位置
	vector v1({ 98,12,45,66,36,27,30,25 });
	v1.erase(v1.begin()); //头删
	v1.erase(v1.end() - 1); //尾删
	v1.erase(v1.begin() + 5); //任意位置删除
	for (auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	// 删除迭代区间
	vector v2(v1);
	v2.erase(v2.begin() + 2, v2.begin() + 5);
	for (auto& e : v2)
	{
		cout << e << " ";
	}
	cout << endl;
    // 在指定位置前插入值为val的元素,比如:66之前插入30,如果没有则不插入
	// 1. 先使用find查找3所在位置
	// 注意:vector没有提供find方法,如果要查找只能使用STL提供的全局find
	auto pos = find(v1.begin(), v1.end(), 66);
	if (pos != v1.end())
	{
		// 2. 在pos位置之前插入30
		v1.insert(pos, 30);
	}
	for (auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

2.2.3 swap

交换两个vector的数据,在string的模拟实现operator=的优化版本则是利用swap,同理vector的模拟实现也可以这样使用。

void swap (vector& x);

2.2.4 operator[ ]

注意:这里返回的对应元素的引用

 reference operator[] (size_type n);
const_reference operator[] (size_type n) const;
void test05()
{
	vector v1({ 98,12,45,66,36,27,30,25 });
	// 获取指定位置的元素
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
}

2.2.5 assign

assign的主要功能是:为字符串分配一个新值,替换其当前内容。

用n个val替换void assign (size_type n, const value_type& val);
用初始化列表数据替换void assign (initializer_list<value_type> il);
用迭代区间的数据替换void assign (iterator first, iterator last);
void test06()
{
	vector v1({ 98,12,45,66,36,27,30,25 });
	v1.assign(10, 1);
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
	v1.assign({ 99,88,77,33,55 });
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
	vector v2 = { 136,232,888 };
	v1.assign(v2.begin(), v2.end());
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
}

3. vector的容量

3.1 size 和 capacity

size:返回有效元素的个数

capacity:返回空间的大小

size_t size();
size_t capacity();
void test07()
{
	vector v1({ 98,12,45,66,36,27,30,25 });
	cout << v1.size() << endl;
	cout << v1.capacity() << endl;
	v1.insert(v1.begin(), 10);
	v1.insert(v1.begin() + 5, 15);
	cout << v1.size() << endl;
	cout << v1.capacity() << endl;
}

3.2 resize 和 reserve

resize():将有效字符的个数变成n个,多出的空间用字符c填充。

reserve():开辟指定大小的空间,当n<size()时,reserver不会改变容量大小。

void resize (size_type n, value_type val = value_type());
void reserve (size_type n);
void test08()
{
	vector v;
	for (int i = 1; i < 10; i++)
		v.push_back(i);
	v.resize(5);
	v.resize(8, 100);
	v.resize(12);
	cout << "v contains:";
	for (size_t i = 0; i < v.size(); i++)
		cout << ' ' << v[i];
	cout << '\n';
}

3.3 vecctor扩容分析

在vs的环境,记录初始空间的大小,不断插入数据记录是否扩容。

void test09()
{
	vector v;
	size_t n;
	n = v.capacity();
	cout << "making bar grow:\n" << endl;
	for (int i = 0; i < 50; i++)
	{
		v.push_back(i);
		if (n != v.capacity())
		{
			n = v.capacity();
            // 扩容
			cout << "capacity changed: " << n << '\n';
		}
	}
}

根据增长的趋势,可以发现在vs环境下,内存扩容大概是以1.5倍增长的!

在linux的环境下,内容扩容趋势大概是以2倍增长的。

4. 迭代器

begin和end:返回指向第一个元素的指针,最后一个元素的下一个位置的指针;

rbegin和rend:获取最后一个数据位置的指针,获取第一个数据前以个位置的指针

void test10()
{
	vector v1({ 98,12,45,66,36,27,30,25 });
	// 利用迭代器遍历
	vector::iterator it = v1.begin();
	while (it != v1.end())
	{
		cout << (*it) << " ";
		it++;
	}
	cout << endl;
	// 范围for -- 底层就是迭代器
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	// for循环
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
	// 使用反向迭代器进行遍历再打印
	// vector::reverse_iterator rit = v.rbegin();
	auto rit = v1.rbegin();
	while (rit != v1.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

迭代器失效将在模拟实现部分讲解!敬请期待~

posted @ 2025-12-06 13:41  clnchanpin  阅读(24)  评论(0)    收藏  举报