STL常用容器-vector容器

vector基本概念

功能:

vector数据结构和数组非常相似,也称为单端数组。

vector和普通数组的区别:

不同之处在于数组是静态空间,而vector可以动态扩展。

动态扩展:

并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间。

vector容器的迭代器是支持随机访问的迭代器。

容量和大小:

capacity(); //容器的容量

size(); //返回容器中元素的个数

vector构造函数

功能描述:创建vector容器

函数原型:

vector<T> v; // 采用模板列来实现,默认的构造函数

vector<T> v(v1.begin(), v1.end());// 将v1[begin(), end())区间中所有的元素拷贝给当前的vector

vector<T> v(n, elem); // 将n个elem元素拷贝给vector容器

vector<T> v(const vector &vec); // 拷贝构造函数,用一个容器对象初始化另外一个容器对象

#include <iostream>
#include <vector> // 使用vector容器时,要引入<vector>。
using namespace std;
void printVector(vector<int> &v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test01()
{
	// 创建一个vector容器
	vector<int> v1; // 无参构造,构建一个vector容器
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i + 1);
	}
	printVector(v1);

	 将v1[begin(),end())区间的所有元素拷贝给当前的容器
	//vector<int> v3(v1.begin(), v1.end());
	//printVector(v3);
	 拷贝构造
	//vector<int> v2(v1);
	//printVector(v2);
	 用5个100对vector容器进行初始化
	//vector<int> v4(5, 100);
	//printVector(v4);
}

vector的赋值操作

功能描述:给vector容器进行赋值

函数原型:

vector &operator=(const vector &vec); //重载赋值操作符

assign函数:

assign(beg,end); // 将参数vector[beg, end)区间中的数据拷贝给当前vector,beg和end是两个位置的指针

assign(n,ele); // 将n个ele拷贝给容器本身

void test02()
{
	vector<int> v1; // 无参构造
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i + 1);
	}
	printVector(v1);

	// 通过赋值运算符来进行容器赋值操作
	vector<int> v2;
	v2 = v1;
	printVector(v2);

	// assign函数实现
	vector<int> v3;
	// begin()是最开始元素的位置,end是最后一个元素的后一个位置,所以begin()+2是指向了第三个元素,end()-2是指向了倒数第二个元素
	v3.assign(v1.begin() + 2, v1.end() - 2);
	printVector(v3);

	// 将5个200拷贝给容器
	vector<int> v4;
	v4.assign(5, 200);
	printVector(v4);
}

vector的容量和大小

功能描述:对vector容器的容量和大小操作

函数原型:

empty(); //判断容器是否为空

capacity(); // 容器的容量,容量相当于装苹果的筐子大小

size(); // 返回容器中的元素个数,size大小相当于苹果筐中的苹果个数

resize(int num); // 重新指定容器长度为num,如果容器变长,则以默认值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除

void test03()
{
	vector<int> v1; // 无参构造
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i + 1);
	}
	printVector(v1);

	if (v1.empty())
	{
		cout << "v1为空" << endl;
	}
	else
	{
		cout << "v1不为空" << endl;
		cout << "v1的容量:" << v1.capacity() << endl;
		cout << "v1的大小:" << v1.size() << endl;
	}
	
	// resize来重新指定容器大小
	v1.resize(5);
	printVector(v1);
	v1.resize(10);
	printVector(v1);
	v1.resize(15, 100);
	printVector(v1);
}

总结:

判断是否为空 --- empty

返回元素个数 --- size

返回容器容量 --- capacity

重新指定大小 --- resize

vector插入和删除

功能描述:对vector容器进行插入、删除操作

函数原型:

尾部操作:

push_back(ele); // 尾部插入元素ele

pop_back(); // 删除最后一个元素

插入insert:

insert(const_iterator pos, ele); // 迭代器指向位置pos插入元素ele,并返回表示新插入元素位置的迭代器

insert(const_iterator pos, int count,ele); // 迭代器指向位置pos插入n个元素ele,并返回表示插新插入的第一个元素位置的迭代器

删除erase:

erase(const_iterator pos); // 删除迭代器所指向的元素,返回被删除元素的下一个元素的迭代器位置

erase(const_iterator start, const_iterator end); // 删除start到end之间的元素,不包括end

clear(); // 删除容器中的所有元素

void test04()
{
	// 尾部插入
	vector<int> v1;
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v1.push_back(40);
	v1.push_back(50);
	printVector(v1);

	// 尾部删除
	v1.pop_back();
	printVector(v1);
	v1.pop_back();
	printVector(v1);

	// 从任意位置来插入
	v1.insert(v1.begin(), 100);
	printVector(v1);
	v1.insert(v1.begin(), 2, 300);
	printVector(v1);

	// 删除
	v1.erase(v1.begin());
	printVector(v1);
	v1.erase(v1.begin(), v1.begin() + 2);
	printVector(v1);

	// 清空元素
	//v1.erase(v1.begin(), v1.end());
	//v1.clear();
	//printVector(v1);

	// 插入insert函数会返回插入新元素的位置,用迭代器来进行接收
	vector<int>::iterator it = v1.insert(v1.begin() + 1, 500);
	printVector(v1);
	cout << *it << endl;
}

总结:

尾插 --- push_back

尾删 --- pop_back

插入 --- insert (位置迭代器)

删除 --- erase (位置迭代器)

清空 --- clear

关于迭代器失效

概念:

vector属于序列式容器,底层是数组,是连续的物理内存空间存储结构,如果发生了插入或者删除的时候,会出现迭代器失效的问题,当失效的情况发生,如果继续操作迭代器,需要先将迭代器进行更新之后才能使用,否则会报错。

出现失效的情况:

insert:

当容量还足够的时候,插入的元素能放下, 不需要重新申请更大的内存空间,插入操作会导致插入位置之后的所有元素位置发生变化,从而导致迭代器失效;

当容量不够的时候,插入元素放不下,需要申请更大的空间来存储元素,会导致整个vector的迭代器失效。

push_back():

当push_back一个元素的时候,end迭代器失效,如果发生了空间扩展,那么全部迭代器失效。

erase:

删除操作不会导致容量不够的问题,但是会导致被删除的当前位置迭代器失效,以及后面所有的迭代器失效,因为删除当前元素之后,后面的元素要前移。

pop_back():

pop_back只会导致end迭代器失效,但是不会影响前面的迭代器,因为其他元素在前面,不需要移动。

// 迭代器失效
void test05()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);
	printVector(v);

	 删除等于30的元素
	//for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	//{
	//	if (*it == 30)
	//	{
	//		v.erase(it); // 这里的删除会导致迭代器发生改变,如果不做调整,会导致出现报错,显示信息无效
	//	}
	//}
	//printVector(v);

	 改进方式:erase方法本身就会返回下一个迭代器的位置,所以it = v.earse(it);
	//for (vector<int>::iterator it = v.begin(); it != v.end();)
	//{
	//	if (*it == 30)
	//	{
	//		it = v.erase(it); // erase会返回下一个元素的迭代器,就相当于it++操作,如果下一个元素也是30下次循环仍然会删除掉
	//	}
	//	else // 不是30的时候才会手动进行it++的操作
	//	{
	//		it++;
	//	}
	//}
	//printVector(v);

	 通过while循环来做
	//vector<int>::iterator it = v.begin();
	//while (it != v.end())
	//{
	//	while (*it == 30)
	//	{
	//		it = v.erase(it);
	//	}
	//	it++;
	//}
	//printVector(v);


	 insert出现迭代器失效的问题
	//for (vector<int>::iterator it = v.begin(); it !=v. end(); it++)
	//{
	//	if (*it == 30)
	//	{
	//		it = v.insert(it, 100);//这里的输入操作会导致迭代器失效,需要更新it
	//		it++; // 这里需要迭代器加1操作,因为上面的insert返回插入的值的迭代器,相当于it-1,指向了100,如果不加1,下次循环体会自动加一次,又指向了30,就变成了一个死循环
	//	}
	//}
	//printVector(v);

	for (vector<int>::iterator it = v.begin(); it != v.end();)
	{
		if (*it == 30)
		{
			it = v.insert(it, 100);//这里的输入操作会导致迭代器失效,需要更新it
			it++; // 这里需要迭代器加1操作,因为上面的insert返回插入的值的迭代器,相当于it-1,指向了100,如果不加1,下次循环体会自动加一次,又指向了30,就变成了一个死循环
			it++;
		}
		else
		{
			it++;
		}
	}
	printVector(v);
}

vector数据存取

功能描述:对vector中的数据的存取操作;

函数原型:

at(int idx); // 返回索引idx所指向的数据

operator[]; // 重载[] , 返回下标所指向的数据

front(); // 返回容器中第一个数据元素

back(); //返回容器中最后一个数据元素

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


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

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

	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1.at(i) << " ";
	}
	cout << endl;

	cout << "第一个元素的值是:" << v1.front() << endl;
	cout << "最后一个元素的值是:" << v1.back() << endl;
}

总结:

除了用迭代器获取vector容器中元素,[ ]和at也可以

front返回容器第一个元素

back返回容器最后一个元素

vector互换容器

功能描述:实现两个容器内元素进行互换

函数原型:

swap(vec); // 将vec与本身的元素互换

利用swap可以实现容器的缩容操作

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

	cout << "v1:";
	printVector(v1);

	vector<int> v2;
	for (int i = 11; i <= 20; i++)
	{
		v2.push_back(i);
	}

	cout << "v2:";
	printVector(v2);

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

	cout << "互换后:" << endl;
	cout << "v1:";
	printVector(v1);
	cout << "v2:";
	printVector(v2);
}

void test03()
{
	vector<int> v;
	for (int i = 0; i < 10000; i++)
	{
		v.push_back(i);
	}

	cout << "v的容量是:" << v.capacity() << endl;
	cout << "v的大小是:" << v.size() << endl;

	v.resize(5);
	cout << "v被重新定义了大小之后结果是:" << v.size() << endl;
	cout << "v的容量不会被影响:" << v.capacity() << endl;

	// 使用swap来实现缩容的操作
	vector<int> v1(v);
	//v.swap(v1); // 让v和v1进行交换,可以实现缩容
	//cout << v.size() << " " << v.capacity() << endl;

	//C++11 提供了一个专门的缩容函数
	v.shrink_to_fit();
	cout << v.size() << " " << v.capacity() << endl;
}

总结:

swap可以使两个容器互换,可以达到实用的收缩内存效果

vector预留空间

功能描述:减少vector在动态扩展容量时的扩展次数,因为数据量如果比较大,那么在运行时时候vector会多次进行内存的开辟,比较消耗资源和时间,所以最好的办法就是开始的时候就直接给vector容器来预留足够的内存,直接给capacity来进行赋值。

函数原型:

reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问。

// vector预留空间
void test04()
{
	vector<int> v;
	// 预留9个位置,如果添加元素到第十个的时候就需要进行扩容了
	v.reserve(9);
	for (int i = 1; i < 11; i++)
	{
		v.push_back(i);
		cout << &v[0] << endl; // 每次都打印同一个值的地址,到第十个的时候地址发生了变化
	}
}

总结:

如果数据量较大,可以一开始利用reserve预留空间

常用算法函数

使用算法的时候需要引入头文件<algorithm>

注意点:算法是引入类库之后可以直接使用,不是vector的成员函数

排序(sort)

sort(iterator beg, iterator end); // 对beg和end区间内的所有的元素进行排序,默认是从小到大

sort(iterator beg, iterator end, func); // 按照func函数对beg和end区间内的所有的元素进行排序

反转(reverse)

reverse(iterator beg, iterator end); // 对beg和end区间内的所有的元素进行反转。

复制(copy)

copy(源起始位置,源的结束位置(不包括这个位置), 目标的起始位置) // 代表选取一段内容赋值到目标的起始位置

查找(find)

find(iterator beg, iterator end,ele); // 在beg和end区间内查找ele元素,如果能找到直接返回对应的迭代器的位置,如果没有找到,返回end迭代器;

注意end指的是区间中指定的end位置,不一定是整个容器的最后的end()

遍历(for each)

for_each(beg, end, func) // 遍历容器,beg和end是容器的迭代器,func是函数或者仿函数,指明跌倒时对元素的操作。

// 排序函数
bool cap(int a, int b)
{
	return a > b;
}

// 用于for_each遍历算法的操作函数
void myPrint(int val)
{
	val++;
	cout << val << " ";
}
// vector算法的使用
void test05()
{
	int arr[] = { 39,40,55,11,23,14,51,20,99,5 };
	vector<int> v;
	v.assign(arr, arr + 10);
	printVector(v);

	// 从小到大来进行排序
	sort(v.begin(), v.end());
	cout << "升序排序后:";
	printVector(v);

	// 从大到小
	// 需要手写一个函数来进行排序操作,这个函数就叫做排序函数
	sort(v.begin(), v.end(), cap);
	cout << "降序排序后:";
	printVector(v);

	cout << "利用for_each来实现遍历值,并且给每一个值进行+1" << endl;
	for_each(v.begin(), v.end(), myPrint);

	// 复制
	vector<int> v2;
	v2.assign(10, 100);
	copy(v.begin(), v.begin() + 5, v2.begin());
	cout << "将v的前5个值赋复制到v2的前5个位置" << endl;
	printVector(v2);

	// 反转
	//reverse(v2.begin(), v2.end());
	reverse(v2.begin(), v2.begin()+5);
	cout << "将v2进行反转之后的结果是:" << endl;
	printVector(v2);

	// 查找
	vector<int>::iterator it = find(v2.begin(), v2.begin() + 5, 55);
	if (it == (v2.begin()+5))
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了,它的下标是:" << it-v2.begin() << endl;
	}
}

总结:

vector是单口容器,所以在尾部进行插入和删除元素的时候效率比较高,访问元素的效率也比较高效,但是在指定位置插入的时候,一定会引起其他元素的移动,所以效率低。

vector的练习

// vector的遍历方法
void test06()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);

	// 使用for循环加迭代器的方式
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;


	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
}

// 在vector中存放自定义数据类型
class Person
{
public:
	string m_Name;
	int m_Age;
	Person(string name, int age) :m_Name(name), m_Age(age) {}
};

void test07()
{
	vector<Person> v;
	Person p1("lucy", 10);
	Person p2("Tom", 20);
	Person p3("lihua", 30);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);

	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "Name:" << (*it).m_Name << "\t" << "Age:" << it->m_Age << endl;
	}
}

// 容器中嵌套容器

void test08()
{
	//创建一个外层容器
	vector<vector<int>> v;

	// 内部容器
	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	vector<int> v4;

	// 给内部容器进行赋值
	for (int i = 0; i < 4; i++)
	{
		v1.push_back(i + 1);
		v2.push_back(i + 2);
		v3.push_back(i + 3);
		v4.push_back(i + 4);
	}
	

	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	v.push_back(v4);

	// 遍历双层容器
	for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
	{
		for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
		{
			cout << *vit << " ";
		}
		cout << endl;
	}
}

// 练习
// 1、给定一个整数类型的vector数组nums,返回每一个数字的平方组成的新动态数组,并且进行升序排列,定义函数来实现
// 例
// nums = [3,6,1,10,9];
// 结果为newNums = [1,9,36,81,100]
vector<int> numPower(vector<int>& v)
{
	vector<int> res;
	for (int i = 0; i < v.size(); i++)
	{
		res.push_back(v[i] * v[i]);
	}
	sort(res.begin(), res.end());
	return res;
}


// 2、给定一个动态数组nums,编写一个函数将所有的0移动到数组的末尾,其他的元素保持原来的相对顺序,直接在原数组上进行操作即可
// nums = [0, 1, 0 ,3 ,12]
// 输出:[1, 3, 12, 0, 0]

void moveZero(vector<int>& v)
{
	// 定义计数器,计算删除了几个0
	int num = 0;
	for (vector<int>::iterator it = v.begin(); it != v.end();)
	{
		// 删除0的时候需要处理迭代失效的问题
		if (*it == 0)
		{
			it = v.erase(it);
			// 每次删除一次0,需要对计数器进行自加操作
			num++;
		}
		else
		{
			it++;
		}
	}
	// 所有的0删除完毕后,在容器的最后进行补0操作
	for (int i = 0; i < num; i++)
	{
		v.push_back(0);
	}

	printVector(v);
}

int main()
{
	vector<int> v;
	v.push_back(0);
	v.push_back(1);
	v.push_back(0);
	v.push_back(3);
	v.push_back(12);
	moveZero(v);

/*	vector<int> v;
	v.push_back(3);
	v.push_back(6);
	v.push_back(1);
	v.push_back(10);
	v.push_back(9);

	vector<int> newNumber = numPower(v);
	for (int i = 0; i < newNumber.size(); i++)
	{
		cout << newNumber[i] << " ";
	}*/
	return 0;
}

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值