STL--线性容器 -vector

Posted 蚍蜉撼树谈何易

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL--线性容器 -vector相关的知识,希望对你有一定的参考价值。

什么是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();
			条目十二《切勿对slt容器的线性安全性又不切实际的依赖》

Problem(I) STL - 灵活的线性表

Problem A: STL——灵活的线性表

C++基础语法梳理:STL 容器(containers)方法及其使用

SGI-STL简记-序列容器(deque)

在stl容器中移除元素的恒定时间