STL--线性容器 -vector

本文详细介绍了C++标准库中的vector容器,包括构造函数(如空初始化、指定大小和区间初始化)、赋值运算符重载、迭代器使用、容量管理(resize、reserve与扩容机制)、元素访问([]和at)、对象修改(push_back、pop_back、insert和erase)以及迭代器失效问题的处理。此外,还提供了vector的模拟实现,帮助读者掌握其实现原理。
摘要由CSDN通过智能技术生成

什么是vector

vector的介绍

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
  6. 与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists(带头结点的双向循环链表)和forward_lists(单向链表)统一的迭代器和引用更好
    vector的文档介绍

探究vector的一些常用函数

构造函数

在这里插入图片描述

void test_constructor()
{
	//1.空构造 vector<type>name;
	vector<int>v1;
	//2.使用n个数字构造 vector<type>name(size_t n,const type&=type())
	vector<int>v2(10, 2);
	//3.区间构造 vector<type>name(iterator first,iterator last)
	int arr[] = { 1,2,3,4,5 };
	vector<int>v3(arr, arr + sizeof(arr) / sizeof(arr[0]));
	//C++11
	vector<int>v4{ 4,5,6,7,8 };
	//拷贝构造
	vector<int>v5(v4);

}

在这里插入图片描述

赋值运算符的重载

void test_fuzhi()
{
	vector<int>v1{ 1,2,3,4,5 };
	vector<int>v2;
	v2 = v1;
}

在这里插入图片描述

迭代器使用

在这里插入图片描述

void test_iterator()
{
	vector<int>v1{ 1,2,3,4,5 };
	auto it = v1.begin();
	while (it != v1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	auto it1 = v1.rbegin();
	while (it1 != v1.rend())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
}

在这里插入图片描述

容量相关的函数及PJ版本下的扩容机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
//测试size()和capacity()

void test_size0capacity()
{
	vector<int>v1{ 1,2,3,4,5 };
	cout << v1.size() << endl;
	cout << v1.capacity() << endl;
}

在这里插入图片描述
//测试resize()

void test_resize()
{
	vector<int>v1{ 1,2,3,4,5 };
	v1.resize(10, 2);
	cout << v1.size() << endl;
	v1.resize(12, 3);

	cout << v1.size() << endl;
}

在这里插入图片描述

//测试reserve()
在这里插入图片描述
//测试扩容机制

void test_extend()
{
	cout << "test for extend" << endl;
	vector<int>v;
	int oldcapacity = v.capacity();
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (oldcapacity != v.capacity())
		{	oldcapacity = v.capacity();
			cout << oldcapacity << " ";
		
		}
	}
	cout << endl;
}

在这里插入图片描述
在vs底下(PJ版本)下为大约1.5倍扩容,在Linux下(SGI版本)下为2倍扩容。

元素获取

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

void test_accessnum()
{
	vector<int>v{ 1,2,3,4,5 };
	//[]运算符访问
	int size = v.size();
	for (int i = 0; i < size; ++i)
	{
		cout << v[i] << " ";
	}
	cout << endl;
	//at 访问
	for (int i = 0; i < size; ++i)
	{
		cout << v.at(i) << " ";
	}
	cout << endl;
	//测试首元素
	cout << v.front() << endl;
	cout << v.back() << endl;
}

在这里插入图片描述
//测试异常的不同
下标运算符’[]’
在这里插入图片描述
at
在这里插入图片描述

vector类对象修改

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
//测试push_back 和pop_back

void test_pop0push()
{
	vector<int>v{ 1,2,3,4,5 };
	auto it = v.begin();
	cout << "before push_back" << endl;
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	cout << "after push_back and before pop_back" << endl;
    v.push_back(6);
	it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	v.pop_back();
	cout << "after pop_back" << endl;
	it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

}

在这里插入图片描述
//测试insert

void test_insert()
{
	vector<int>v{ 1,2,3,4,5 };
	auto it = v.begin();
	//插入单个元素iterator insert ( iterator position, const T& x );
	v.insert(it + 2, 6);//在3的前面插入6
	it = v.begin();
	// void insert ( iterator position, size_type n, const T& x ); 插入多个相同的元素
	
	v.insert(it + 2, 5, 1);
	it = v.begin();
	//void insert ( iterator position, InputIterator first, InputIterator last ); 插入区间内的一段元素 区间左闭右开 [first,last)
	int arr[] = { 7,8,9,10 };
	v.insert(it, arr, arr + sizeof(arr) / sizeof(arr[0]));
	it = v.begin();
	it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

在这里插入图片描述
//测试erase

void test_erase()
{
	vector<int>v{ 1,2,3,4,5 };
	auto it = v.begin();
	int arr[] = { 7,8,9,10 };
	v.insert(it, arr, arr + sizeof(arr) / sizeof(arr[0]));
	it = v.begin();
	//删除某一位置单个元素iterator erase ( iterator position );
	v.erase(it);
	//删除某一区间的值 iterator erase ( iterator first, iterator last );
	it = v.begin();
	v.erase(it, it + 3);
	it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;


}

在这里插入图片描述
//测试clear 和swap

void test_swap0clear()
{
	vector<int>v{ 1,2,3,4,5 };
	vector<int>v1{ 2,3,4,5 };
	//测试clear()
	cout << "before clear" << endl;
	cout <<"v1的有效元素个数为"<< v1.size() << endl;
	v1.clear();
	cout << "after clear" << endl;
	cout << "v1的有效元素个数为 " << v1.size() << endl;
	//测试swap
	cout << "before swap" << endl;
	cout << "v的有效元素个数为" << v.size() << endl;
	cout << "v1的有效元素个数为" << v1.size() << endl;
	v.swap(v1);
	cout << "after swap" << endl;
	cout << "v的有效元素个数为" << v.size() << endl;
	cout << "v1的有效元素个数为" << v1.size() << endl;

	
}

在这里插入图片描述

探究vector种迭代器失效的问题

1,所有的插入操作都可能会引起迭代器的失效。
在这里插入图片描述
2.erase删除某个位置上的元素,成功删除之后迭代器失效。
原因:vector中在删除一个元素后,迭代器会自动指向下一个元素,很可能导致迭代器越界。

void test_iteratoruseless()
{
	vector<int>v{ 1,2,3,4,5 };
	auto it = v.begin();
	while (it != v.end())
	{
		v.erase(it);
		it++;
	}
}

在这里插入图片描述
解决方法:利用返回值,重新赋值。在erase操作之后,当前位置迭代器失效,返回下一位置的迭代器。

void test_iteratoruseless()
{
	vector<int>v{ 1,2,3,4,5 };
	auto it = v.begin();
	while (it != v.end())
	{
		it=v.erase(it);
		
	}
}

3.swap会造成迭代器失效

在这里插入图片描述
解决方法:
在swap()操作后重新给迭代器变量赋值。

模拟实现vector

namespace myvector
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
	public:
		//无参构造
		vector() :start(nullptr), finish(nullptr), endofstorage(nullptr)
		{

		}
		//n个元素
		vector(size_t n, const T& data = T())
			:start(new T[n]),
			 finish(start + n),
			 endofstorage(start+n)
		{
			for (int i = 0; i < n; ++i)
			{
				start[i] = data;
			}
		}
		//区间构造
		template<class Iterator>
		vector(Iterator first, Iterator end)
		{
			size_t n = 0;
			auto it = first;
			while (it != end)
			{
				++n;
				++it;
			}
			start = new T[n];
			finish = endofstorage = start + n;
			for (int i = 0; i < n; ++i)
			{
				start[i] = first[i];
			}

		}
		//拷贝构造
		vector(vector<T>& t1)
		{
			int n = t1.size();
			T* temp = new T[n];
			for (int i = 0; i < n; ++i)
			{
				temp[i] = t1[i];
			}
			start = temp;
			finish = endofstorage = start + n;

		}
		//赋值运算符的重载
		vector<T>& operator=(vector<T>& t1)
		{
			if (begin() != t1.begin())
			{
				if (!empty())
				{
					delete[]start;
				}
				int n = t1.size();
				T* temp = new T[n];
				for (int i = 0; i < n; ++i)
				{
					temp[i] = t1[i];
				}
				start = temp;
				finish = start+n;
				endofstorage = start + t1.capacity();
			}
		}
		~vector()
		{
			if (start != nullptr)
			{
				delete[]start;
				start = finish = endofstorage = nullptr;
			}
		}
	public:
		//迭代器的使用
		iterator begin()
		{
			return  start;
		}
		iterator end()
		{
			return finish();
		}
	public:
		//容量相关
		size_t size()const
		{
			return finish - start;
		}
		size_t capacity()const
		{
			return endofstorage - start;
		}
		bool empty()
		{
			return start == finish;
		}
		void resize(int n, const T& t1 = T())
		{
			int oldsize = size();
			if (n > oldsize)
			{
				if (n > capacity())
				{
					reserve(n);
				}
				for (int i = oldsize; i < n; i++)
				{
					start[i] = t1;
				}
			}
			finish = start + n;
		}
		void reserve(int cal)
		{
			int oldcapacity = capacity();
			if (cal > oldcapacity)
			{
				int oldsize = size();
				T* temp = new T[cal];
				for (int i = 0; i < oldsize; ++i)
				{
					temp[i] = start[i];
				}
				delete[]start;
				start = temp;
				finish = start + oldsize;
				endofstorage = start + cal;
			}

		}
	public:
		//元素访问
		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 start[0];
		}
		const T& front()const
		{
			return start[0];
		}
		T& back()
		{
			return start[size() - 1];
		}
		const T& back()const
		{
			return *(finish - 1);
		}
		void push_back(const T& t1)
		{
			if (size() == capacity())
			{
				reserve(capacity() * 2 + 3);
			}
			*finish = t1;
			++finish;
		}
		void pop_back()
		{
			if (empty())
			{
				return;
			}
			--finish;
		}
		iterator insert(iterator pos, const T& t1)
		{
			if (size() == capacity())
			{
				reserve(capacity() * 2 + 3);
			}
			if (pos > finish)
			{
				pos = finish;
				*finish = t1;
				++finish;
			}
			else 
			{
				iterator it = finish;  // it元素要搬移到的位置
				while (it != pos)
				{
					*it = *(it - 1);
					--it;
				}

				*pos = data;
				++finish;
				
				
			}
			return pos;
		}
		iterator erase(iterator pos)
		{
			if (pos == end())
				return pos;

			iterator it = pos;   // 元素要搬移到的位置
			while (it != finish)
			{
				*it = *(it + 1);
				++it;
			}

			--finish;
			return pos;
		}
		T& operator*(iterator pos)
		{
			return *pos;
		}
		iterator erase(iterator pos, iterator pos1)
		{
			finish = pos;
		}
		void clear()
		{
			finish = start;
		}
		void swap(vector<T>& t1)
		{
			std::swap(start, t1.start);
			std::swap(finish, t1.finish);
			std::swap(endofstorage, t1.endofstorage);
		}
		



	private:
		iterator start;
		iterator finish;
		iterator endofstorage;
	};
};

测试用例:

void test()
{
	myvector::vector<int>vv;
	vv.push_back(1);
	vv.push_back(2);
	vv.push_back(3);
	vv.push_back(4);
	cout << vv.front() << endl;
	cout << vv.back() << endl;
	cout << vv.capacity() << endl;
	cout << vv.size() << endl;
	myvector::vector<int>vv1(vv);
	cout << vv1.front() << endl;
	cout << vv.back() << endl;
	int arr[] = { 1,2,3,4,5 };

	myvector::vector<int>vv2(arr,arr+3);
	
	cout << vv2.front() << endl;
	cout << vv2.back() << endl;
	auto it = vv.begin();
	cout << *it << endl;
    	
}

在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值