C++之vector

C++之vector


在这里插入图片描述

1.vector介绍

  • vector表示可变大小数组的序列容器
  • 采用连续的空间存储元素,并且大小是动态可以改变的。
  • vector使用动态分配数组来存储元素,当插入新元素时,这个数组要分配一个新的数组增大空间,再将所有元素移至新的数组中。
  • 与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和forward_lists统一的迭代器和引用更好。

2.vector使用及vector模拟实现

1.vector的定义:
构造函数声明接口说明
vector()无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector(const vector& x)拷贝构造
vector(InputIterator first,InputIterator last)使用迭代器进行初始化构造
//无参构造
		vector()
			:start(nullptr)
			, finish(nullptr)
			, end_of_storage(nullptr)
		{}
//构造函数
		vector(size_t n,const T& value=	T)
			:start(new T[n])
			, finish(start)
			, end_of_storagr(start+n)
		{
			for (size_t i = 0; i < n;i++){
				*finish++ = value;
			}
		}
//拷贝构造
		vector(const vector<T>& v))
			:start(nullptr)
			, finish(nullptr)
			, end_of_storage(nullptr)
		{
			vector<T> temp(v.cbegin(),v.cend());
			this->swap(temp);
		}
//迭代器初始化
		template<class Iterator>
		vector(Iterator first,Iterator last){
			size_t n = bite::disstance(first,last);
			start = new T[n];
			finish = start;
			end_of_storage = start + n;

			while (first != last)
			{
				*finish = *first;
				finish++;
				first++;
			}
					vector<T>& operator=(vector<T> v)
		{
			this->swap(v);
			return *this;
		}
//析构函数
		~vector()
		{
			if (start)
			{
				delete[] start;
				start = nullptr;
				finish = nullptr;
				end_of_storage = nullptr;
			}
		}

		}
2.vector iterator 的使用
iterator使用接口说明
begin + end获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator
rbegin + rend获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator

如下图;
在这里插入图片描述

iterator begin(){
			retirn start;
		}

		iterator end(){
			return finish;
		}

		reverse_iterator rbegin()
		{
			return end();
		}

		reverse_iterator rend()
		{
			return begin();
		}
3.vector 空间增长问题
容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize改变vector的size
reserve将vector放入capacity
//获取数据个数
		size_t size()const{
			return finish - start;
		}
//获取容量大小
		size_t capacity()const{
			return end_of_storage - start;
		}
//判空
		bool empty()const{
			return finish == start;
		}
//改变vector的size
		void resize(size_t newsize,const T& value=T()){
			size_t oldsize = size();
			if (newsize>oldsize){
				size_t oldcapacity = capacity();
				if (newsize>oldcapacity){
					reserve(newsize);
				}
				for (size_t i = oldsize; i < newsize;++i){
					start[i] = value;
				}
			}
			finish = start + newsize;
		}
//将vector放入capacity
		void reserve(size_t newcapacity){
			size_t oldcapacity = capacity();
			size_t n = size();
			if (newcapacity>oldcapacity){
				T* temp = new T[newcapacity];
				if (start){
					for (size)t i = 0; i < n;i++){
						temp[i] = start[i];
					}
				}
				start = temp;
				finish = start + n;
				end_of_storage = start + newcapacity;
			}
		}
4.vector增删查改
vector增删查改接口说明
push_back尾插
pop_back尾删
find查找(自己实现,不是vector成员接口)
insert在position之前插入val
erase删除position未知的数据
swap交换两个vector的数据空间
operator[]重载使像数组一样访问
//重载为可以数组一样访问
T& operator[](size_t index){
			assert(index<size());
			return start[index];
		}

		const T& operator[](size_t index)const
		{
			assert(index<size());
			return start[index];
		}
//头
		T& front(){
			return *begin();
		}

		const T& front()const
		{
			return *begin();
		}
//尾
		T& back(){
			return *(finish-1);
		}

		const T& back()const
		{
			return *(finish - 1);
		}
//尾插
		void push_back(const T& value){
			if (finish==end_of_storage){
				reserve(capacity()*2+3);
			}
			*finish = value;
			++finish;
		}
//尾删
		void pop_back(){
			if (empty()){
				return;
			}
			--finish;
		}
//插入
		iterator insert(interator pos,const T& value){
			if (pos<start||pos>finish){
				return pos;
			}
			if (finish==end_of_storage){
				reserve(capacity()*2);
			}
			auto it = finish - 1;
			while (it>=pos){
				*(it + 1) = *it;
				it--;
			}

			*ppos = value;
			++finish;
			return pos;
		}
//删除
		iterator erase(iterator pos){
			if (pos<start||pos>=finish){
				return end();
			}
			auto it = pos + 1;
			while (it<finish){
				*(it - 1) = *it;
				it++;
			}
			finish--;
			return pos;
		}
//清理
		void clear(){
			finish = start;
		}
5.vector的扩容机制

看以下代码:

  • VS下运行:
void TestPushBack(){
		vector<int> v;
		size_t sz = v.capacity();
		for (size_t i = 0; i < 100;i++){
			v.push_back(i);
			if (sz!=v.capacity()){
				sz = v.capacity();
				cout << sz << endl;
			}
		}
	}

在这里插入图片描述

  • Linux下运行:

在这里插入图片描述

在这里插入图片描述

结论:

  • vs中vector是按照1.5倍的方式扩容,Linux下vector是按照2倍的方式扩容
  • 如果在使用vector之前,可以预估vector中大概可以放多少个元素,最好提前将空间开辟好,否则vector是边插入边扩容,成本很大。

3.迭代器失效

1.什么是迭代器
  • 迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装
2.为什么迭代器会失效
  • 比如:vector的迭代器就是原生态指针T*。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间(迭代器对应的指针指向了非法空间),造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
3.哪些操作会导致迭代器失效
  • 所有可能会导致扩容操作的方法都可能会导致迭代器失效,如:push_back、insert、assign、reserve、resize、operator=
void TestIterator(){
		vector<int> v{1,2,3,4,5,6};
		vector<int>::iterator it = v.begin();

		v.push_back(7);
		v.push_back(8);
		v.push_back(9);

		while (it != v.end()){
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

在这里插入图片描述

原因:上面说过,vector增加元素需要扩容,而扩容会重新分配一个新的空间,而不是原来的指向,扩容成功后原来的空间就失效了

解决方法

void TestIterator(){
		vector<int> v{1,2,3,4,5,6};
		vector<int>::iterator it = v.begin();

		v.push_back(7);
		v.push_back(8);
		v.push_back(9);

		it = v.begin();//使用迭代器前给迭代器重新赋值
		while (it != v.end()){
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}
  • iterator erase(iterator position)、iterator erase(iterator first,iterator last),这些进行删除操作的时候
void TestErase(){
		vector<int> v{1,2,3,4,5,6,7};
		auto it = v.begin();
		while (it!=v.end()){
			v.erase(it);
			++it;
		}
	}

在这里插入图片描述
原因:直接删除it会导致指向消失,再++的时候就无法找到这块空间

解决方案

oid TestErase(){
		vector<int> v{1,2,3,4,5,6,7};
		auto it = v.begin();
		while (it!=v.end()){
			/*v.erase(it);
			++it;*/
			it = v.erase(it);
		}
	}

即vs中,erase将position迭代器位置的元素删除后,该position迭代器就i失效了,erase返回下一个元素的位置

  • swap,在交换的时候不注意迭代器的指向也容易出错
void TestSwap()
	{
		vector<int> v1{1,2,3,4,5};
		vector<int> v2{6,7,8,9,0};
		auto it1 = v1.begin();
		auto it2 = v2.begin();

		v1.swap(v2);

		while (it1!=v1.end()){
			cout << *it1 << " ";
			++it1;
		}
		cout << endl;

		while (it2 != v2.end()){
			cout << *it2 << " ";
			++it2;
		}
		cout << endl;
	}

在这里插入图片描述

原因:swap之后,v1与v2的迭代器指针的指向也已经交换了,如果还指向原来的迭代器,指向的就是非法空间

解决方案:

void TestSwap()
	{
		vector<int> v1{1,2,3,4,5};
		vector<int> v2{6,7,8,9,0};
		auto it1 = v1.begin();
		auto it2 = v2.begin();

		v1.swap(v2);

		it1 = v1.begin();//交换后给迭代器重新赋值
		it2 = v2.begin();

		while (it1!=v1.end()){
			cout << *it1 << " ";
			++it1;
		}
		cout << endl;

		while (it2 != v2.end()){
			cout << *it2 << " ";
			++it2;
		}
		cout << endl;
	}
  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值