Vector

vector简介


vector是序列式容器(sequence containers)中的一种。


向量(vector)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。 

vector的数据安排以及操作方式,与array非常相似。两者唯一的差别在于空间的运用的灵活性。array是静态空间,一旦配置了就不能改变。vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。因此,vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,我们再也不必因为害怕空间不足而一开始就要求一个大块头array了,我们可以安心使用vector,吃多少用多少。

vector的数据结构

vector所采用的数据结构非常简单:线性连续空间。它以两个迭代器start和finish分别指向配置得来的连续空间中目前已经被使用的范围(符合STL规范之"前闭后开"区间),并以迭代器end_of_storage指向整块连续空间(含备用空间)的尾端。

另外在vector当中具有容量(capacity)的概念,这是为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求量更大一些,以备将来可能的扩充。换而言之,一个vector的容量永远大于或等于其大小。一旦容量等于大小,便是满载,下次再有新增元素,整个vector就得另觅居所。

在vector当中包含三个迭代器成员变量,分别是:

  • iterator start                       // 表示目前使用空间的头

  • iterator finish                     // 表示目前使用空间的尾

  • iterator end_of_storage    // 表示目前可用空间的尾 

下面通过一个测试程序来观察一下vector的特性:

#include 
#include 
#include 
using namespace std;

int main()
{
	vector iv(2, 9);
	cout << "size=" << iv.size() << endl;			// size=2
	cout << "capacity=" << iv.capacity() << endl;	// capacity=2

	iv.push_back(1);
	cout << "size=" << iv.size() << endl;			// size=3
	cout << "capacity=" << iv.capacity() << endl;	// capacity=3

	iv.push_back(2);
	cout << "size=" << iv.size() << endl;			// size=4
	cout << "capacity=" << iv.capacity() << endl;	// capacity=4

	iv.push_back(3);
	cout << "size=" << iv.size() << endl;			// size=5
	cout << "capacity=" << iv.capacity() << endl;	// capacity=6

	iv.push_back(4);
	cout << "size=" << iv.size() << endl;			// size=6
	cout << "capacity=" << iv.capacity() << endl;	// capacity=6

	for (auto i : iv)
		cout << i << " ";							// 9 9 1 2 3 4
	cout << endl;

	iv.push_back(5);
	cout << "size=" << iv.size() << endl;			// size=7
	cout << "capacity=" << iv.capacity() << endl;	// capacity=9

	for (auto i : iv)
		cout << i << " ";							// 9 9 1 2 3 4 5
	cout << endl;

	iv.pop_back();
	iv.pop_back();
	cout << "size=" << iv.size() << endl;			// size=5
	cout << "capacity=" << iv.capacity() << endl;	// capacity=9

	iv.pop_back();
	cout << "size=" << iv.size() << endl;			// size=4
	cout << "capacity=" << iv.capacity() << endl;	// capacity=9

	vector::iterator ivite = find(iv.begin(), iv.end(), 1);
	if (ivite != iv.end())
		iv.erase(ivite);
	cout << "size=" << iv.size() << endl;			// size=3
	cout << "capacity=" << iv.capacity() << endl;	// capacity=9
	for (auto i : iv)
		cout << i << " ";							// 9 9 2
	cout << endl;

	ivite = find(iv.begin(), iv.end(), 2);
	if (ivite != iv.end())
		iv.insert(ivite, 3, 7);
	cout << "size=" << iv.size() << endl;			// size=6
	cout << "capacity=" << iv.capacity() << endl;	// capacity=9
	for (auto i : iv)
		cout << i << " ";							// 9 9 7 7 7 2
	cout << endl;

	iv.clear();
	cout << "size=" << iv.size() << endl;			// size=0
	cout << "capacity=" << iv.capacity() << endl;	// capacity=9
	return 0;
}

通过测试结构我们能够看到,vector会在满载后的下一次插入操作时进行动态扩容,在我的编译器下扩容的倍数为1.5倍,不同编译器具体不同,在STL源码剖析一书当中的扩容倍数为2。

这里需要注意的是,所谓动态增加大小,并不是在原空间之后接续新空间(因为无法保证原空间之后尚可有可供配置的空间),而是以原大小的两倍配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。

因此,对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。这是程序员易犯的一个错误,务需小心。

注意事项:在使用迭代器遍历操作vector时,切记不要在循环内部进行任何改变vector大小的操作,一旦引起数据空间重新配置或数据移动,则会造成迭代器失效的状况,进而引发无法预知的错误。

vector的常用操作

构造函数:

  • vector():创建一个空vector
  • vector(int nSize):创建一个vector,元素个数为nSize
  • vector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为t
  • vector(const vector&):复制构造函数
  • vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中
#include 
#include 
#include 
using namespace std;

int main()
{
	vector ivec1;					// 创建一个空vector
	cout << "size=" << ivec1.size() << endl;			// size=0
	cout << "capacity=" << ivec1.capacity() << endl;	// capacity=0 

	vector ivec2(5);				// 创建一个vector,元素个数为nSize(这里需要注意的是,所有的元素会被默认初始化)
	cout << "size=" << ivec2.size() << endl;			// size=5
	cout << "capacity=" << ivec2.capacity() << endl;	// capacity=5 
	for (auto i : ivec2)
		cout << i << " ";				// 0 0 0 0 0 				
	cout << endl;

	vector ivec3(6, 6);			// 创建一个vector,元素个数为nSize,且值均为t(所有元素默认值为t)
	cout << "size=" << ivec3.size() << endl;			// size=6
	cout << "capacity=" << ivec3.capacity() << endl;	// capacity=6 
	for (auto i : ivec3)
		cout << i << " ";				// 6 6 6 6 6 6		
	cout << endl;

	vector ivec4(ivec3);			// 复制构造函数
	cout << "size=" << ivec4.size() << endl;			// size=6
	cout << "capacity=" << ivec4.capacity() << endl;	// capacity=6 
	for (auto i : ivec4)
		cout << i << " ";				// 6 6 6 6 6 6		
	cout << endl;

	const int length = 5;
	int a[length] = { 5, 4, 3, 2, 1 };
	vector ivec5(a, a + length);	// 复制[begin, end)区间内另一个数组的元素到vector中
	cout << "size=" << ivec5.size() << endl;			// size=5
	cout << "capacity=" << ivec5.capacity() << endl;	// capacity=5 
	for (auto i : ivec5)
		cout << i << " ";				// 5 4 3 2 1
	cout << endl;
}

 

插入函数:

  • void push_back(const T& x):向量尾部增加一个元素X
  • iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x(前插法)
  • iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
  • iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
#include 
#include 
#include 
using namespace std;

int main()
{
	vector ivec = { 0, 1, 2, 3, 4, 5 };
	ivec.push_back(6);	// 向量尾部增加一个元素X

	vector::iterator ivecite = find(ivec.begin(), ivec.end(), 3);
	if (ivecite != ivec.end())
		ivec.insert(ivecite, 99);	// 向量中迭代器指向元素前增加一个元素x(前插法)
	for (auto i : ivec)
		cout << i << " ";	// 0 1 2 99 3 4 5
	cout << endl;

	ivecite = find(ivec.begin(), ivec.end(), 99);
	if (ivecite != ivec.end())
		ivec.insert(ivecite, 3, 9);	// 向量中迭代器指向元素前增加n个相同的元素x
	for (auto i : ivec)
		cout << i << " ";	// 0 1 2 9 9 9 99 3 4 5
	cout << endl;

	const int length = 3;
	int a[length] = { 3, 2, 1 };
	ivec.insert(ivec.begin(), a, a + length);	// 向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
	for (auto i : ivec)
		cout << i << " ";	// 3 2 1 0 1 2 9 9 9 99 3 4 5
	cout << endl;
}

删除函数:

  • iterator erase(iterator it):删除向量中迭代器指向元素,并返回指向下一个元素的迭代器
  • iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
  • void pop_back():删除向量中最后一个元素(vector为空时会出错,因此事先需进行判空检查)
  • void clear():清空向量中所有元素
#include 
#include 
#include 
using namespace std;

int main()
{
	vector ivec = { 0, 1, 2, 3, 4, 5 };
	auto ivecite = find(ivec.begin(), ivec.end(), 4);
	if (ivecite != ivec.end())				// 删除向量中迭代器指向元素,并返回指向下一个元素的迭代器
		cout << *(ivec.erase(ivecite)) << endl;		// 5
	cout << "size=" << ivec.size() << endl;			// size=5
	cout << "capacity=" << ivec.capacity() << endl;	// capacity=6
	for (auto i : ivec)
		cout << i << " ";	// 0 1 2 3 5
	cout << endl;

	ivecite = find(ivec.begin(), ivec.end(), 3);
	if (ivecite != ivec.end())
		ivec.erase(ivecite, ivec.end());	// 删除向量中[first,last)中元素
	cout << "size=" << ivec.size() << endl;			// size=3
	cout << "capacity=" << ivec.capacity() << endl;	// capacity=6
	for (auto i : ivec)
		cout << i << " ";	// 0 1 2
	cout << endl;

	if (!ivec.empty())
		ivec.pop_back();	// 删除向量中最后一个元素
	cout << "size=" << ivec.size() << endl;			// size=2
	cout << "capacity=" << ivec.capacity() << endl;	// capacity=6
	for (auto i : ivec)
		cout << i << " ";	// 0 1
	cout << endl;

	ivec.clear();	// 清空向量中所有元素
	cout << "size=" << ivec.size() << endl;			// size=0
	cout << "capacity=" << ivec.capacity() << endl;	// capacity=6
	ivec.pop_back();
}

遍历函数:

  • reference at(int pos):返回pos位置元素的引用
  • reference front():返回首元素的引用
  • reference back():返回尾元素的引用
  • iterator begin():返回向量头指针,指向第一个元素
  • iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
  • reverse_iterator rbegin():反向迭代器,指向最后一个元素
  • reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
#include 
#include 
#include 
using namespace std;

int main()
{
	vector ivec = { 0, 1, 2, 3, 4, 5 };
	cout << ivec.at(2) << endl;	// 2 返回pos位置元素的引用
	cout << ivec[2] << endl;	// 2

	cout << ivec.front() << endl;	// 0 返回首元素的引用
	cout << ivec.back() << endl;	// 5 返回尾元素的引用

	auto first = ivec.begin();		// 返回向量头指针,指向第一个元素
	auto last = ivec.end();			// 返回向量尾指针,指向向量最后一个元素的下一个位置
	for (; first != last; ++first)
		cout << *first << " ";		// 0 1 2 3 4 5
	cout << endl;

	auto r_first = ivec.rbegin();	// 反向迭代器,指向最后一个元素
	auto r_last = ivec.rend();		// 反向迭代器,指向第一个元素之前的位置
	for (; r_first != r_last; ++r_first)
		cout << *r_first << " ";	// 5 4 3 2 1 0
	cout << endl;

	vector ivec2(ivec.rbegin(), ivec.rend());
	for (auto i : ivec2)
		cout << i << " ";			// 5 4 3 2 1 0
	cout << endl;
}

判断函数:

  • bool empty() const:判断向量是否为空,若为空,则向量中无元素
#include 
#include 
#include 
using namespace std;

int main()
{
	vector ivec;
	if (ivec.empty())    // 判断向量是否为空,若为空,则向量中无元素
		cout << "ivec is empty!" << endl;
}

 

你可能感兴趣的:(C++)