vector以及list

18 篇文章 0 订阅

之前已经学习过了string类,接下来介绍c++中的另外两个类—— vector和list;

vector

之前介绍的string类是c++所特定的字符数组;

而vector可以看做是string类的扩展,因为它是一个模板类;

它可以作为任何类型的数组,比如 int ,char,string等等类型;

 但是和c语言中的数组不同的是,它是可变的;

vector的特性

1.是可变大小的序列容器

2.vector是采用连续存储空间来存储元素,可以随机访问,但是大小被容器自动处理

3.vector尾插尾删效率高,但是其他位置的删除和插入就不行了

vector的使用方式

vector<类型名> <变量名>

#include<iostream>
#include<vector>

using namespace std;

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	
	int n = v1.size();

	for (int i = 0; i < n; i++)
	{
		cout << v1[i];
	}

	cout << endl;

	return 0;
}

 

 通过string的学习,实际上就已经了解了vector的大部分函数了;

vector唯一和string不一样的就是string可以直接输出,而vector只能一个一个输出;

vector的初始化方式

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

int main()
{
	vector<int> v1;
	vector<int> v2(5);
	vector<int> v3(5, 0);
	vector<int> v4(v3);

	return 0;
}

v1就是单纯的创建一个vector<int> 的数组;

v2则是创建一个初始空间大小为 5 的数组;

v3是创建一个初始空间大小为5,且全部数据为0的数组;

v4则是拷贝一个v3大小,数据的数组;

而我们之前在C语言中,我们都需要提前开辟一定的空间,且这个空间是固定的;

c++中的vector却可以有多种多样的方式来开辟空间。

vector的错误使用方式

vector<int> v1;
	vector<int> v2(5);
	vector<int> v3(5, 0);
	vector<int> v4(v3);

	v1[0] = 1;//错误的,没有开辟空间
	v2[0] = 1;//v2以及后面的v3,v4都是正确的,都开辟了对应的空间
	v3[0] = 1;
	v4[0] = 1;

vector和c语言中的数组一样,必须要先开辟空间才能存储数据,就像上面的v1,没有开辟空间,就无法进行下标访问修改;

而vector被称为变长数组的原因归功于它的函数——push_back;

	v1.push_back(1);//正确的,会自动开辟空间
	v2[0] = 1;//v2以及后面的v3,v4都是正确的,都开辟了对应的空间
	v3[0] = 1;
	v4[0] = 1;

push_back的函数实现中,会自动开辟空间,因而实现变长;

vector存储自定义变量

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

int main()
{
	vector<vector<int>> v1;
	return 0;
}

由于vector是类模板,当然也可以存储类成员变量,而我们一旦像上面一样使用vector,就一定要记住要么直接push_back一个类成员,要么先开辟对应的空间再使用下标赋值,否则很容易出错;

vector的迭代器失效(string通用)

每个容器都有迭代器,而迭代器是一个类似于指针的东西,因此迭代器在一些场景会出现失效的情况;

情况1:引起底层空间改变的操作 

vector和string这种连续存储的容器的扩容并不是在原来的空间上扩容

 而是新开辟一个更大的空间,然后将数据放到原来的空间,然后释放原空间;

但是我们的迭代器若是未及时更新,就会导致迭代器指向无效空间;

而当我们使用 resize,resere,insert,assign,push_back 等函数的时候;

就可能会导致底层空间需要扩容;

这样我们的迭代器就会失效;

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

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	vector<int>::iterator iv1 = v1.begin() + 2;
	
	v1.reserve(30);
	cout << *iv1 << endl;

	cout << endl;


	return 0;
}

我们可以看到,iv1 迭代器指向的地址已经失效了,无法输出;

因此我们使用迭代器的时候,一定要注意迭代器是否失效;

这种情况string也会出现,因此我们在使用容器的迭代器的时候,一定要注意时刻更新迭代器;

而我们都知道当 vector 的容器存满了内容后会自动扩容;

而它的扩容又是开辟新空间;

因此当我们的迭代器出现问题的时候,可能就是我们的容器扩容了,而迭代器位置为更新的原因

情况2:指定位置删除操作——erase

void test2()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	vector<int>::iterator iv1 = v1.end();
	v1.erase(iv1);
	cout << *iv1 << endl;

}

这里是因为我们的迭代器指向了容器的尾端;

而若是我们删除了迭代器所在位置,那么迭代器就会指向了end的位置,从而导致迭代器失效了;

迭代器失效的解决方式:对迭代器重新赋值

list

list 和 vector 以及 string 不一样,它并不是在一片连续的空间的,而是随取随用;

这意味着 list 无法随机访问;

而 list 底层是一个双向循环链表,这使得 list 的头插头删尾插尾删都十分方便快捷;

并且,list 也是一个模板类,可以指定不同类型的 list 变量;

list的使用

void test3()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(1);
	l1.push_back(1);
	list<int>::iterator il1 = l1.begin();
	while (il1 != l1.end())
	{
		cout << *il1 << ' ';
		il1++;
	}
	cout << endl;
}

list的各种成员函数

之前提到过,list的无法随机访问,也就是说list无法通过下标来访问成员;

但是除此之外,list 的成员函数的使用方式和之前的vector,list 都是一样的;

 

不管是构造函数,还是头插尾插啥的,使用方式都是一样的;

list的迭代器失效

list 的迭代器失效只在 list 删除时会出现;

之前说过,list 是一个双向循环链表;

而链表的每一个节点都是独立的,只是通过指针来链接罢了;

那么这也就说明,list 的 erase 的底层实现和别的容器不同;

list 的 erase  是释放该位置的节点然后返回下一个节点的位置

而之前的 vector 和 string 都是在连续的一片空间存储

erase都是将该位置的数据用后面的数据覆盖

因此只要 erase 的位置不是最后一个,或者说没有扩容,就不会导致迭代器失效;

这也就说明, list 的 erase 会随时随地导致迭代器失效;

void test3()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(1);
	l1.push_back(1);
	list<int>::iterator il1 = l1.begin();
	while (il1 != l1.end())
	{
		l1.erase(il1);
		il1++;
	}
	cout << endl;
}

比如这里,我们将 il1 的位置删除了,那么就直接导致迭代器失效了;

 而我们若是想清空 list 的元素,应该这样做:

void test3()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(1);
	l1.push_back(1);
	list<int>::iterator il1 = l1.begin();
	while (il1 != l1.end())
	{
		il1 = l1.erase(il1);
		
	}
	cout << endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值