C++ STL(三):vector容器


1 vector基本概念

作用单端数组,仅可在容器的尾部插入或删除元素,与数组非常相似。
区别普通数组静态空间vector支持动态扩展容量机制。

动态扩展:并非在原有内存空间中扩展新空间,而是申请更大的内存空间,将原有数据拷贝至新的内存空间,并释放原有内存空间

vector容器的迭代器:支持随机访问的迭代器,可跳跃式访问容器元素。
vector容器
push_back()尾插法插入数据。
pop_back()尾删法删除数据。
front():获取vector容器的第1个元素
back():获取vector容器的最后1个元素
begin():获取起始迭代器,指向容器中的第1个元素
end():获取结束迭代器,指向容器中的最后1个元素下一个位置


2 vector构造函数

作用:创建vector容器。

注:使用vector容器时,需包含头文件#include <vector>

函数原型
(1)vector<T> v;:默认无参构造函数,采用类模板实现。
(2)vector(v.begin(), v.end());:拷贝容器对象v[begin(), end())区间左闭右开,包左不包右)的元素进行初始化。
(3)vector(n, elem);:有参构造函数,使用nelem元素进行初始化。
(4)vector(const vector &vec);:拷贝构造函数,使用已有vector对象初始化新的对象。

注:通常使用默认无参构造函数拷贝构造函数实例化vector容器对象。

示例:vector构造函数

#include <iostream>
using namespace std;
#include <vector>	//包含头文件

//打印vector元素的函数模板
template<typename T>
void printVector(vector<T>& v) {
    
    
	//for循环遍历
	for (vector<T>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << (*it) << " ";
	}
	cout << endl;
}

int main() {
    
    
	/* 1.默认无参构造函数 */
	vector<int> v1;

	//尾插法插入元素
	for (int i = 0; i < 5; i++) {
    
    
		v1.push_back(i);
	}
	//遍历
	printVector<int>(v1);	//0 1 2 3 4

	/* 2.有参构造,区间拷贝 */
	//左闭右开区间的元素
	vector<int> v2(v1.begin(), v1.end());
	printVector<int>(v2);	//0 1 2 3 4

	/* 3.n个elem元素赋值 */
	//5个整型元素6
	vector<int> v3(5, 6);
	printVector<int>(v3);	//6 6 6 6 6

	/* 4.拷贝构造函数 */
	vector<int> v4(v3);
	printVector<int>(v4);	//6 6 6 6 6

	return 0;
}

3 vector赋值操作【operator=、assign()】

作用:通过重载赋值运算符operator=成员函数assign(),对vector容器进行赋值。

函数原型
(1)vector& operator=(const vector &vec);:重载赋值运算符,使用目标vector容器,对当前vector容器赋值。
(2)assign(begin, end);:拷贝目标vector容器中[begin(), end())区间左闭右开,包左不包右)的元素,对当前vector容器赋值。
(3)assign(n, elem);:使用nelem元素,对当前vector容器赋值。

示例:vector赋值操作

#include <iostream>
using namespace std;
#include <vector>	//包含头文件

//打印vector元素的函数模板
template<typename T>
void printVector(vector<T>& v) {
    
    
	//for循环遍历
	for (vector<T>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << (*it) << " ";
	}
	cout << endl;
}


int main() {
    
    
	vector<int> v;

	//尾插法插入元素
	for (int i = 0; i < 5; i++) {
    
    
		v.push_back(i);
	}
	//遍历
	printVector<int>(v);	//0 1 2 3 4

	/* 1.重载运算符=赋值 */
	vector<int> v1 = v;
	printVector<int>(v1);	//0 1 2 3 4

	/* 2.assign()函数,区间拷贝 */
	//左闭右开区间的元素
	vector<int> v2;
	v2.assign(v.begin(), v.end());
	printVector<int>(v2);	//0 1 2 3 4

	/* 3.assign()函数,n个elem元素赋值 */
	vector<int> v3;
	//6个整型元素6
	v3.assign(6, 6);
	printVector<int>(v3);	//6 6 6 6 6 6

	return 0;
}

4 vector容量【capacity()】和大小【size()、resize()】

作用:操作vector容器的容量大小(即元素个数)。

注:容器的容量始终大于等于容器的大小(即元素个数),并支持动态扩展容量

函数原型
(1)empty();:判断容器是否为空。
(2)capacity();:获取容器的容量
(3)size();:获取容器的大小,即元素个数
(4)resize(int num);重新指定容器的长度为num
若容器变长,则以默认值0填充新位置;若容器变短,则容器末尾超出新长度的元素被删除
(5)resize(int num, elem);重新指定容器的长度为num
若容器变长,则以指定值elem填充新位置;若容器变短,则容器末尾超出新长度的元素被删除

示例:vector容量和大小

#include <iostream>
using namespace std;
#include <vector>	//包含头文件

//打印vector元素的函数模板
template<typename T>
void printVector(vector<T>& v) {
    
    
	//for循环遍历
	for (vector<T>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << (*it) << " ";
	}
	cout << endl;
}

int main() {
    
    
	vector<int> v1;
	//尾插法插入元素
	for (int i = 0; i < 5; i++) {
    
    
		v1.push_back(i);
	}
	printVector<int>(v1);	//0 1 2 3 4

	//empty():判断容器是否为空
	cout << (v1.empty() ? "v1为空" : "v1不为空") << endl;	//v1不为空

	//capacity(); :获取容器的容量。
	cout << "v1的容量:" << v1.capacity() << endl;		//6(随机值)
	
	//size(); :获取容器的大小,即元素个数。
	cout << "v1的大小/元素个数:" << v1.size() << endl;	//5

	//resize(int num);:重新指定容器的长度为num
	//若容器变长,则以默认值0填充新位置;若容器变短,则容器末尾超出新长度的元素被删除。
	v1.resize(10);			//长度变大时,使用默认值0填充
	printVector<int>(v1);	//0 1 2 3 4 0 0 0 0 0

	v1.resize(3);			//长度变小时,容器末尾超出新长度的元素被删除
	printVector<int>(v1);	//0 1 2

	//resize(int num, elem); :重新指定容器的长度为num。
	//若容器变长,则以指定值elem填充新位置;若容器变短,则容器末尾超出新长度的元素被删除。
	v1.resize(8, 6);		//长度变大时,使用指定值6填充
	printVector<int>(v1);	//0 1 2 6 6 6 6 6

	return 0;
}

5 vector插入【push_back()、insert()】和删除【pop_back()、erase()、clear()】

(1)vector容器插入元素:使用成员函数push_back(..)insert(..)向vector容器插入元素。

函数原型
push_back(ele);尾插法,向vector容器的尾部插入元素ele
insert(const_iterator pos, ele);迭代器指向位置pos插入元素ele
insert(const_iterator pos, int n, ele);迭代器指向位置pos插入n个元素ele


(2)vector容器删除元素:使用成员函数pop_back(..)erase(..)clear(..)删除vector容器中的元素。

函数原型
pop_back();尾删法,删除vector容器尾部的最后1个元素
erase(const_iterator pos);:删除迭代器指向位置的元素。
erase(const_iterator start, const_iterator end);:删除迭代器指向位置[start, end)区间的所有元素。
clear();:清空容器中的所有元素

注1:清空容器的所有元素,v.clear();等价于v.erase(v.begin(), v.end());
注2:插入元素insert(..)、删除元素erase(..)均需要迭代器对象作为参数。

示例:vector插入和删除元素

#include <iostream>
using namespace std;
#include <vector>	//包含头文件

//打印vector元素的函数模板
template<typename T>
void printVector(vector<T>& v) {
    
    
	//for循环遍历
	for (vector<T>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << (*it) << " ";
	}
	cout << endl;
}

int main() {
    
    
	vector<int> v;
	
	//插入元素:push_back()
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	printVector<int>(v);	//1 2 3 4 5

	//删除元素:pop_back()
	v.pop_back();
	printVector<int>(v);	//1 2 3 4

	//插入元素:insert(const_iterator pos, ele); 迭代器指向位置pos插入元素ele
	//在起始迭代器的指向位置插入元素10
	v.insert(v.begin(), 10);
	printVector<int>(v);	//10 1 2 3 4

	//插入元素:insert(const_iterator pos, int n, ele); 迭代器指向位置pos插入n个元素ele。
	//在起始迭代器的指向位置插入2个元素0
	v.insert(v.begin(), 2 , 0);
	printVector<int>(v);	//0 0 10 1 2 3 4

	//删除元素:erase(const_iterator pos); 删除迭代器指向位置的元素
	//删除起始迭代器的指向位置的元素
	v.erase(v.begin());	
	printVector<int>(v);	//0 10 1 2 3 4

	//删除元素:erase(const_iterator start, const_iterator end); 删除迭代器指向位置[start, end)区间的所有元素。
	//删除起始迭代器后一个位置 至 结束迭代器 之间区间的所有元素
	v.erase(++v.begin(), v.end());
	printVector<int>(v);	//0

	//清空元素:clear(); 清空容器中的所有元素。
	v.clear();
	printVector<int>(v);	//(空)
	
	return 0;
}

6 vector数据存取【operator[]、at()】

作用:通过重载赋值运算符operator[]成员函数at(int index),对vector容器的单个元素进行(作为右值)或(作为左值)。

函数原型
(1)operator[](int index);:重载运算符[],读写指定索引位置index的元素。
(2)at(int index);:成员函数,读写指定索引位置index的元素。
(3)front();:返回容器的第1个元素
(4)back();:返回容器的最后1个元素

访问/遍历vector容器元素的方式
迭代器
重载运算符[]
成员函数at()

示例:vector读写元素

#include <iostream>
using namespace std;
#include <vector>	//包含头文件

//打印vector元素的函数模板
template<typename T>
void printVector(vector<T>& v) {
    
    
	//for循环遍历
	for (vector<T>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << (*it) << " ";
	}
	cout << endl;
}


int main() {
    
    
	vector<int> v;
	//尾插法插入元素
	for (int i = 0; i < 5; i++) {
    
    
		v.push_back(i);
	}

	//遍历方式1:重载运算符
	for (int i = 0; i < v.size(); i++) {
    
    
		//重载运算符[]:读写指定索引位置index的元素。
		cout << v[i] << " ";		//0 1 2 3 4
	}
	cout << endl;

	//遍历方式2:成员函数at()
	for (int i = 0; i < v.size(); i++) {
    
    
		//重载运算符[]:读写指定索引位置index的元素。
		cout << v.at(i) << " ";		//0 1 2 3 4
	}
	cout << endl;
	
	//修改元素1:重载运算符
	v[4] *= 10;
	printVector<int>(v);	//0 1 2 3 40

	//修改元素2:成员函数at()
	v.at(0) = -1;
	printVector<int>(v);	//-1 1 2 3 40

	//获取第1个元素
	cout << "第1个元素:" << v.front() << endl;	//-1

	//获取最后1个元素
	cout << "最后1个元素:" << v.back() << endl;	//40

	return 0;
}

7 vector互换容器【swap()】

函数原型swap(vec);:将目标vector容器vec的元素与自身互换。

作用
(1)实现两个vector容器的元素互换


(2)可结合匿名对象拷贝构造函数,实现容器内存收缩,如:vector<int>(v).swap(v);
背景:当容量较大的vector容器,使用成员函数resize()将容器的大小(元素个数)调整至较小值时,vector容器实际容量不变,导致内存资源浪费
内存收缩步骤
vector<int>(v):调用拷贝构造函数创建vector类的匿名对象,将根据原vector容器对象v的大小(元素个数)分配一定的容量(较小值)。
vector<int>(v).swap(v);:原vector对象v和匿名对象实现容器互换,即指针指向的内存地址互换,匿名对象指向具有较大容量的内存空间。
匿名对象调用完毕后立即释放,对应的较大容量的内存空间被自动释放。
④原vector对象v现指向具有较小容量的内存空间,实现容器内存收缩
vector容器互换-收缩容器内存

示例:vector容器互换

#include <iostream>
using namespace std;
#include <vector>	//包含头文件

//打印vector元素的函数模板
template<typename T>
void printVector(vector<T>& v) {
    
    
	//for循环遍历
	for (vector<T>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << (*it) << " ";
	}
	cout << endl;
}

//vector容器互换
void func1() {
    
    
	vector<int> v1;
	for (int i = 0; i < 5; i++) {
    
    
		v1.push_back(i);
	}

	vector<int> v2;
	for (int i = 4; i >= 0; i--) {
    
    
		v2.push_back(i);
	}

	cout << "交换前v1容器:" << endl;
	printVector<int>(v1);	//0 1 2 3 4
	cout << "交换前v2容器:" << endl;
	printVector<int>(v2);	//4 3 2 1 0

	//容器互换
	v1.swap(v2);

	cout << "交换后v1容器:" << endl;
	printVector<int>(v1);	//4 3 2 1 0
	cout << "交换后v2容器:" << endl;
	printVector<int>(v2);	//0 1 2 3 4
}


//实际作用:vector容器内存收缩
void func2(){
    
    
	//现有容器v开始时具有较大容量和较多元素
	vector<int> v;
	for (int i = 0; i < 100000; i++) {
    
    
		v.push_back(i);
	}
	cout << "resize前..." << endl;
	cout << "v的容量:" << v.capacity() << endl;	//容量:138255
	cout << "v的大小:" << v.size() << endl;		//大小:100000

	/* resize() 重新指定大小,长度为5 */
	v.resize(5);

	//resize容器大小后,容量保持【较大值】不变,容器大小变为【较小值】
	//内存资源浪费
	cout << "resize后..." << endl;
	cout << "v的容量:" << v.capacity() << endl;	//容量:138255
	cout << "v的大小:" << v.size() << endl;		//大小:5
	
	/* 创建匿名对象,并进行容器互换 */
	vector<int>(v).swap(v);

	//容器互换后,原vector容器的容量和大小均变为【较小值】,实现容器内存收缩
	//匿名对象调用完毕后立即释放,指向的较大内存空间被释放
	cout << "容器互换后..." << endl;
	cout << "v的容量:" << v.capacity() << endl;	//容量:5
	cout << "v的大小:" << v.size() << endl;		//大小:5
}

int main() {
    
    
	//func1();
	func2();

	return 0;
}

8 vector预留空间【reserve()】

作用:当vector容器存储的数据量较大时,一开始可利用成员函数reserve()预留指定大小的内存空间,减少vector容器在动态扩展容量时的扩展次数,降低数据拷贝过程的资源消耗。

函数原型
reserve(int len);:容器预留len个元素长度的内存空间,但预留内存空间不进行初始化不可访问

注:reserve(...)reverse()需注意区分。
reserve(...)用于vector容器预留空间
reverse(...)用于反转容器的元素,如reverse(v.begin(), v.end());

示例:vector预留空间

#include <iostream>
using namespace std;
#include <vector>	//包含头文件

//vector预留空间
void func() {
    
    
	vector<int> v;

	/* 预留空间 */
	//v.reserve(10000);		//动态扩展7次
	//v.reserve(20000);		//动态扩展5次
	//v.reserve(50000);		//动态扩展3次
	v.reserve(100000);		//动态扩展1次

	//统计vector插入100000个元素时,动态扩展容量的总次数
	int count = 0;
	//初始化空指针,用于判断是否动态扩展
	int* p = NULL;

	for (int i = 0; i < 100000; i++) {
    
    
		v.push_back(i);

		//判断指向vector容器首元素的指针,记录的地址值是否发生改变
		//首地址发生改变 → vector容器已动态扩展
		if (p != &v[0]) {
    
    
			//更新指针的地址值
			p = &v[0];
			count++;
			//cout << "vector容器的首地址:" << p << endl;
		}
	}
	cout << "动态扩展容量的总次数:" << count << endl;
	//未预留空间时:动态扩展30次
	//预留10000个元素长度时:动态扩展7次
	//预留20000个元素长度时:动态扩展5次
	//预留50000个元素长度时:动态扩展3次
	//预留100000个元素长度时:动态扩展1次
}

int main() {
    
    
	func();

	return 0;
}

猜你喜欢

转载自blog.csdn.net/newson92/article/details/113930670