STL(3)---<vector>

vector是STL中最常见的容器,它是一种顺序容器,支持随机访问。vector是一块连续分配的内存,从数据安排的角度来讲,和数组极其相似,不同的地方就是:数组是静态分配空间,一旦分配了空间的大小,就不可再改变了;而vector是动态分配空间,随着元素的不断插入,它会按照自身的一套机制不断扩充自身的容量。

vector的扩充机制:按照容器现在容量的一倍进行增长。vector容器分配的是一块连续的内存空间,每次容器的增长,并不是在原有连续的内存空间后再进行简单的叠加,而是重新申请一块更大的新内存,并把现有容器中的元素逐个复制过去,然后销毁旧的内存。这时原有指向旧内存空间的迭代器已经失效,所以当操作容器时,迭代器要及时更新。

vector数据结构,采用的是连续的线性空间,属于线性存储。他采用3个迭代器_First、_Last、_End来指向分配来的线性空间的不同范围

下面是我提取出的一些源码和自己的理解

#include "allocator.h"

//vector容器是一个模板类,可以存放任何类型的对象(但必须是同一类对象)vector对象可以在运行时高效地添加元素,并且vector中元素是连续存储的。
//这里我所提出的源码中没有const迭代器和反向迭代器,而且后边对于vector的一个特化的范例bool型也没有列出

namespace w
{	// TEMPLATE CLASS vector

	template<class _Ty, class _A = allocator<_Ty> >
		class vector {
public:
	typedef vector<_Ty,_A> _Myt;//只在类中有效的类型重定义

public:
	typedef _A allocator_Type;
	typedef _A::difference_type difference_Type;
	typedef _A::pointer _Tptr;
	//	typedef _A::const _Ctptr;
	typedef _A::reference reference;
	//	typedef _A::const_reference const_reference;
	typedef _A::value_type value_type;
	typedef _Tptr iterator;//对于向量无需对指针进行包装组成迭代器,指针本省作为迭代器
	//	typedef _Ctptr const_iterator;

	explicit vector(const _A& _Al = _A())//构造函数产生默认的vector对象但是不能隐式类型转换
		: allocator(_Al), _First(0), _Last(0), _End(0) {}
	explicit vector(size_t _N, const _Ty& _V = _Ty(),//产生_N个值为_V的对象
		       const _A& _Al = _A())
		       : allocator(_Al)
	{_First = allocator.allocate(_N, (void *)0);
	_Ufill(_First, _N, _V);
	_Last = _First + _N;
	_End = _Last; }
	vector(const _Myt& _X)//拷贝构造函数
		: allocator(_X.allocator)
	{_First = allocator.allocate(_X.size(), (void *)0);
	_Last = _Ucopy(_X.begin(), _X.end(), _First);
	_End = _Last; }
	typedef iterator _It;
	vector(_It _F, _It _L, const _A& _Al = _A())//用一段数据来初始化
		: allocator(_Al), _First(0), _Last(0), _End(0)
	{insert(begin(), _F, _L); }
	~vector()
	{
	_Destroy(_First, _Last);
	allocator.deallocate(_First, _End - _First);
	_First = 0, _Last = 0, _End = 0;
	}
	_Myt& operator=(const _Myt& _x)//赋值函数
	{
		if(&_x != this)
		{
			if(_x.size() <= size())
			{
				iterator _s=copy(_x.begin(),_x.end(),_First);
				_Destroy(_s,_Last);
				_Last =_First + _x.size();
			}
			else if(_x.size() <= _x.capacity())
			{
				iterator _s = _x.begin()+size();
				copy(_x.begin(), _s, _First);
				_Ucopy(_s, _x.end(), _Last);
			     _Last = _First + _x.size();
			}
		}
		return *this;
	}
	void reserve(size_t _N)// 确保capacity() >= _N
	{
	if (capacity() < _N)//小于就重新分配之后将原数据复制过来
	{
	 iterator _S = allocator.allocate(_N, (void *)0);
	_Ucopy(_First, _Last, _S);
	_Destroy(_First, _Last);
	allocator.deallocate(_First, _End - _First);
	_End = _S + _N;
	_Last = _S + size();
	_First = _S;
	}
	}
	size_t capacity() const// 容器能够存储的元素个数,有:capacity() >= size()
	{return (_First == 0 ? 0 : _End - _First); }
	iterator begin()
	{return (_First); }

	iterator end()//注意是返回一个指向被控序列末端的下一个位置的迭代器
	{return (_Last); }
	///////////reverse//////////////
	void resize(size_t _N, const _Ty& _X = _Ty())// 确保返回后,有:size() == n;如果之前size()<n,那么用元素x的值补全。
	{if (size() < _N)
	insert(end(), _N - size(), _X);
	else if (_N < size())
		erase(begin() + _N, end()); }
	size_t size() const // 返回容器中元素个数
	{return (_First == 0 ? 0 : _Last - _First); }
	size_t max_size() const // 返回容器能容纳的最大元素个数
	{return (allocator.max_size()); }
	bool empty() const// 如果为容器为空,返回true;否则返回false
	{return (size() == 0); }
	_A get_allocator() const//返回空间配置器
	{return (allocator); }
	reference at(size_t _P)const//这个使用起来比重载的[]更加安全
	{  // 返回下标为pos的元素的引用;如果下标不正确,则抛出异常out_of_range
		if(size()<=_P)//这里要有等于相当于判断数组是否越界的
		{
			_Xran();//抛出异常
		}
		return (*(begin()+_P));
	}
	reference operator[](size_t _P)// 返回下标为pos的元素的引用(下标从0开始;如果下标不正确,则属于未定义行为
	{return (*(begin() + _P)); }
	reference front() // 返回容器中第一个元素的引用(容器必须非空)
	{return (*begin()); }

	reference back()// 返回容器中最后一个元素的引用(容器必须非空)
	{return (*(end() - 1)); }
	void push_back(const _Ty& _X)// 向容器末尾添加一个元素
	{insert(end(), _X); }
	void pop_back()  // 弹出容器中最后一个元素(容器必须非空)
	{erase(end() - 1); }
	void assign(_It _F, _It _L)
	{erase(begin(), end());
	insert(begin(), _F, _L); }
	void assign(size_t _N, const _Ty& _X = _Ty()) // 赋值,用指定元素序列替换容器内所有元素
	{erase(begin(), end());
	insert(begin(), _N, _X); }
	// 注:下面的插入和删除操作将发生元素的移动(为了保持连续存储的性质),所以之前的迭代器可能失效
	iterator insert(iterator _P,const _Ty&_x=_Ty())//插入后并返回插入的那个数据的地址
	{ // 在插入点元素之前插入元素(或者说在插入点插入元素)
		size_t tmp =_P -begin();
		insert(_P,1,_x);
		return(begin()+tmp);
	}
	void insert(iterator _P,size_t _N,const _Ty&_x=_Ty())//从一个位置开始向后面插入_N个相同的数据_x
	{// 注意迭代器可能不再有效(可能重新分配空间)
		if(_End - _First < _N)//如果创建的空间容量中(还未用的空间和已经用的)不足以满足_N个数据的存储
		{
			size_t _M =size()+(_N<size() ? size():_N);//分配的内存至少是原来的一倍
			iterator _s= allocator.allocate(_M,(void*)0);//分配内存
			iterator _q =_Ucopy(_First,_P,_s);//原来的数据拷贝到新的内存中
			//这里_Ucopy()返回的是将原数据拷贝完后的下一个内存空间的迭代器

			_Ufill(_q,_N,_x);//用_N个_x填满拷贝完原数据后余下的内存空间
			_Destroy(_First,_Last);//析构原来的对象
			allocator.deallocate(_First,_End -_First);//释放原来的内存,此时_End还指向原来的内存容量处

			_End = _s+_M;//把_End的指向改变一下
			_Last = _s+size()+_N;

			_First =_s;
		}
		else if(_Last - _P < _N)//此时要在原数据的_P到_End之间插入_N个数据,就是不必要再冲洗分配内存
		{
			_Ucopy(_P,_Last,_P+_N);//将原来的数据中_P到_last之间有的数据向后移动_N位
			_Ufill(_Last,_N-(_Last-_P),_x);//首先解释_P有可能指向原来的数据的某一个位置,但是_P到了_last之间的数据
			//不够_N所以会向外走,这就话就是用_x来填满外边的这些个数位置
			fill(_P,_Last,_x);//把里面的用_x填满

			_Last += _N;//注意哟,就是 _last =_last+_N;

		}
		else if(0<_N)//这个就是一开始没有数据的时候,要分配空间的
		{
			_Ucopy(_Last - _N,_Last,_Last);
			copy_backward(_P,_Last-_N,_Last);
			fill(_P,_P+_N,_x);
			_Last += _N;
		}
	}

	void insert(iterator _P,_It _F,_It _L)//在_P迭代器所指的空间的后边插入后边两个迭代器的数据范围
	{
		size_t _M =0;
		_Distance(_F,_L,_M);//计算两个迭代器之间的元素个数
		if (_End - _Last < _M)
		{
			size_t _N = size() + (_M < size() ? size() : _M);
			iterator _S = allocator.allocate(_N, (void *)0);
			iterator _Q = _Ucopy(_First, _P, _S);//原来的数据复制到新的空间
			_Q = _Ucopy(_F, _L, _Q);//再把_F 到_L所指的数据复制到新的空间上
			_Ucopy(_P, _Last, _Q);//再把_P 到_last的原来的数据复制到新的空间

			_Destroy(_First, _Last);
			allocator.deallocate(_First, _End - _First);
			_End = _S + _N;
			_Last = _S + size() + _M;
			_First = _S;
		}
		else if (_Last - _P < _M)
		{
			_Ucopy(_P, _Last, _P + _M);//复制相当于把原来的数据后移每次都是创建一个节点
			_Ucopy(_F + (_Last - _P), _L, _last);//先把后半段复制过来
			copy(_F, _F + (_Last - _P), _P);//再把前半段复制过来
			_Last += _M;
		}
		else if (0 < _M)
		{
			_Ucopy(_Last - _M, _Last, _Last);
			copy_backward(_P, _last - _M, _Last);
			copy(_F, _L, _P);
			_Last += _M;
		}
	}
	iterator erase(iterator _P) // 删除指定元素,并返回删除元素后一个元素的位置(如果无元素,返回end())
	{copy(_P + 1, end(), _P);
	_Destroy(_Last - 1, _Last);
	--_Last;
	return (_P); }

	iterator erase(iterator _F, iterator _L)// 注意:删除元素后,删除点之后的元素对应的迭代器不再有效。
	{iterator _S = copy(_L, end(), _F);
	_Destroy(_S, end());
	_Last = _S;
	return (_F); }
	void clear()
	{erase(begin(), end()); }
	bool _Eq(const _Myt& _X) const//判断相等
	{return (size() == _X.size()
	&& equal(begin(), end(), _X.begin())); }

	bool _Lt(const _Myt& _X) const//判断不等
	{return (lexicographical_compare(begin(), end(),
	_X.begin(), _X.end())); }
	void swap(_Myt& _X)//判断是不是使用的同一个空间配置器
	{                   //交换对象
		if (allocator == _X.allocator)
		{
			std::swap(_First, _X._First);
			std::swap(_Last, _X._Last);
			std::swap(_End, _X._End);
		}
		else//否则直接将两个对象交换
		{
			_Myt _Ts = *this;
			*this = _X,
				_X = _Ts;
		}
	}
	friend void swap(_Myt& _X, _Myt& _Y)
	{_X.swap(_Y); }
protected:
	void _Destroy(iterator _F, iterator _L)
	{for (; _F != _L; ++_F)
	allocator.destroy(_F); }
	iterator _Ucopy(iterator _F, iterator _L,
		iterator _P)
	{for (; _F != _L; ++_P, ++_F)
	allocator.construct(_P, *_F);
		return (_P); }
	void _Ufill(iterator _F, size_t _N, const _Ty &_X)
		{for (; 0 < _N; --_N, ++_F)
			allocator.construct(_F, _X); }
	void _Xran() const
		{_THROW(out_of_range, "invalid vector<T> subscript"); }

	_A allocator;
	iterator _First, _Last, _End;
        //_First指向使用空间的头部,
        //_last指向使用空间大小(size)的尾部
        //_End指向空间容量(capacity)的尾部
 };

//	vector对象的比较(非成员函数)

  // 针对vector对象的比较有六个比较运算符:
  //operator==、operator!=、operator<、operator<=、operator>、operator>=。
template<class _Ty, class _A> inline
	bool operator==(const vector<_Ty, _A>& _X,
		const vector<_Ty, _A>& _Y)
	{return (_X._Eq(_Y)); }
template<class _Ty, class _A> inline
	bool operator!=(const vector<_Ty, _A>& _X,
		const vector<_Ty, _A>& _Y)
	{return (!(_X == _Y)); }
template<class _Ty, class _A> inline
	bool operator<(const vector<_Ty, _A>& _X,
		const vector<_Ty, _A>& _Y)
	{return (_X._Lt(_Y)); }
template<class _Ty, class _A> inline
	bool operator>(const vector<_Ty, _A>& _X,
		const vector<_Ty, _A>& _Y)
	{return (_Y < _X); }
template<class _Ty, class _A> inline
	bool operator<=(const vector<_Ty, _A>& _X,
		const vector<_Ty, _A>& _Y)
	{return (!(_Y < _X)); }
template<class _Ty, class _A> inline
	bool operator>=(const vector<_Ty, _A>& _X,
		const vector<_Ty, _A>& _Y)
	{return (!(_X < _Y)); }

}
//allocator.h

//#include <cstdlib>//包含ptrdiff_t(int),size_t
//#include <new>   //包含 placement new
namespace k
{
	// TEMPLATE FUNCTION _Allocate
	template<class _Ty> inline
		_Ty *_Allocate(ptrdiff_t _N, _Ty *)
	{
		if (_N < 0)
			_N = 0;
		return ((_Ty *)operator new((ptrdiff_t)_N * sizeof (_Ty)));
	}

	// TEMPLATE FUNCTION _Construct
	template<class _T1, class _T2> inline
		void _Construct(_T1  *_P, const _T2& _V)
	{   new ((void*)_P) _T1(_V); }//placement new,调用T1的构造函数构造对象
	     //new(_P) _T1(value);

	// TEMPLATE FUNCTION _Destroy

	template<class _Ty> inline
	void _Destroy(_Ty *_P)
	{   _P->~Ty(); }
	// TEMPLATE CLASS allocator

	template<class _Ty>
		class allocator{
public:
	typedef size_t        size_type;
	typedef ptrdiff_t     difference_type;
	typedef _Ty*          pointer;
   //typedef const _Ty*    const_pointer;
	typedef _Ty&          reference;
	//typedef const _Ty&    const_reference;
	typedef _Ty           value_type;

	pointer address(reference _X) const
	{return (&_X); }//返回对象地址
//	const_pointer address(const_reference _X) const
//	{return (&_X); } //返回常对象地址
	pointer allocate(size_type _N, const void *)
	{return (_Allocate((difference_type)_N,(pointer)0)); }
	char *_Charalloc(size_type _N)
	{return (_Allocate((difference_type)_N,(char*)0)); }
	void deallocate(void *_P, size_type)
	{operator delete(_P); }
	void construct(pointer _P, const _Ty& _V)
	{_Construct(_P, _V); }
	void destroy(pointer _P)
	{_Destroy(_P); }
	size_type max_size() const
	{
		size_type _N = (size_type)(-1) / sizeof (_Ty);//类型除以-1是该类型中所能表示的最大无符号值
		return (0 < _N ? _N : 1);
	}

	};

}
下面是vector的一些用法:
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector< int > a ;
    for(int i=0;i<10;++i)
	{
		a.push_back(i);
	}
	for( i = 0; i < a.size(); i++ )//v.size() 表示vector存入元素的个数
	{
		cout << a.at(i) << "  "; //把每个元素显示出来
	}
	cout<<endl;
	for( i=0;i<a.size();i++)
	{
		cout<<a[i]<<" ";
	}
cout<<endl;
	vector<int> vv;
	vv.reserve(10);//reserve()分配了10个int型的空间,但并没有初始化
	for( i=0; i<7; i++)
		vv.push_back(i);
	try
	{
		int iVal1 = vv[7];  // not bounds checked - will not throw
		int iVal2 = vv.at(7); // bounds checked - will throw if out of range
	}
	catch(const exception& e)
	{
		cout << e.what();
	}
cout<<endl;
	vector<int>::iterator iter;
	for(iter = a.begin(); iter != a.end();++iter)
	{
		cout<<*iter<<" ";
	}
	cout<<endl;
 //建立一个10行的列可变的二维数组

  vector<vector<int> > arr(10,vector<int>(0));//vector<int>(0)是对vector初始化,否则不能对vector存入元素。
   for(i=0;i<10;++i)
   {
	   for(int j=0;j<9;++j)
	   {
		   arr[j].push_back(i);
	   }
   }

   for(i=0;i<10;++i)
   {
	   for(int j=0;j<arr[i].size();++j)
	   {
            cout<<arr[i][j]<<" ";
	   }
   }
	cout<<endl;
   //建立一个行列都能变化的数组

   vector<vector<int> > arry;
   vector<int> n;

   for(i=0;i<10;++i)
   {
	   arry.push_back(n);//要对每一个vector初始化,否则不能存入元素。
    for(int j=0;j<9;++j)
	{
		arry[i].push_back(j);
	}

   }
   for(i=0;i<10;++i)
   {
	   for(int j=0;j<arry[i].size();++j)
	   {
		   cout<<arry[i][j]<<" ";
	   }
   }

   cout<<endl;

    vector<int> v(5, 1);
	v.insert(v.begin() + 3, 1, 2);
    v.insert(v.begin() + 4, 1, 3);
    v.insert(v.begin() + 5, 1, 4);

    v.insert(v.begin() + 6, 1, 5);

    cout<<"> After insert"<<endl;
    for( i = 0; i < v.size(); ++i)
        cout<<v[i]<<" ";
	cout<<endl;
	vector<int>::iterator it1 = v.erase(v.begin() + 3, v.begin() + 6);//删除的是第4,5,6三个元素
    cout<<"> After erase"<<endl;
    for( i = 0; i != v.size(); ++i)//*it1 =5;
        cout<<v[i]<<" ";
	cout<<endl;
		return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-02 14:27:45

STL(3)---<vector>的相关文章

【C++】STL,vector容器操作

C++内置的数组支持容器的机制,但是它不支持容器抽象的语义.要解决此问题我们自己实现这样的类.在标准C++中,用容器向量(vector)实现.容器向量也是一个类模板.标准库vector类型使用需要的头文件:#include <vector>.vector 是一个类模板.不是一种数据类型,vector<int>是一种数据类型.Vector的存储空间是连续的,list不是连续存储的. 一. 定义和初始化vector< typeName > v1;       //默认v1为

STL之vector

今天学习了STL 以前用的c,可是比赛回来发现c有点弱,c++的stl是比较实用的,适合比赛.所以学习了一下. vector. 这是一个容器,其实就是线性表. 使用之前在头部加上#include <vector> 然后就可以使用 vector<type> vec; //type is a kind of basic type (eg. int double ..) 然后访问这个表的时候需要声明一个变量 vector<type>::iterator ite; 然后就可以用

C++ STL:vector

  不定长数组:vetor 它就像一个二维数组,只是第一维的大小是固定的,但是第二维的大小不固定. 下面是一些尝试代码: 1. <pre name="code" class="cpp"> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<vec

带你深入理解STL之Vector容器

C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. STL实现了一个Vector容器,该容器就是来改善数组的缺点.vector是一个动态空间,随着元素的加入,它的内部机制会自行扩充以容纳新元素.因此,vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,再也不必因为害怕空间不足而一开始就配置一个大容量数组了,vector是用多少就分配多少. 要

【STL】- vector的使用

初始化: 1. 默认构造: vector<int> vint; 2. 用包含10个元素的数组初始化: vector<int> vint(ia, ia+10); 算法: 1. vint.push_back(i); 2. vint.size(); 3. vint[i]; 代码: 1 #include <vector> 2 #include <iostream> 3 using namespace std; 4 5 int ia[] = {123,1,32,53,

【STL】vector的insert方法详解

#include<vector> #include<iostream> using namespace std; int main() { vector<int> v(3); v[0]=2; v[1]=7; v[2]=9; v.insert(v.begin(),8);//在最前面插入新元素. v.insert(v.begin()+2,1);//在迭代器中第二个元素前插入新元素 v.insert(v.end(),3);//在向量末尾追加新元素. vector<int

C++的STL中vector内存分配方法的简单探索

STL中vector什么时候会自动分配内存,又是怎么分配的呢? 环境:Linux  CentOS 5.2 1.代码 #include <vector> #include <stdio.h> using namespace std; int main() { vector<int> x_vec; printf("data size : [%3d], mem size : [%3d]\n", x_vec.size(), x_vec.capacity())

STL容器 vector,list,deque 性能比较

C++的STL模板库中提供了3种容器类:vector,list,deque对于这三种容器,在觉得好用的同时,经常会让我们困惑应该选择哪一种来实现我们的逻辑.在少量数据操作的程序中随便哪一种用起来感觉差别并不是很大,但是当数据达到一定数量后,会明显感觉性能上有很大差异. 本文就试图从介绍,以及性能比较两个方面来讨论这个问题. vector - 会自动增长的数组 list - 擅长插入删除的链表 deque - 拥有vector和list两者优点的双端队列 性能竞技场 性能总结与使用建议 测试程序清

STL学习——Vector篇

STL学习--Vector篇 vector简介 vector的数据安排及操作方式与array非常相似,两者的区别在于空间运用的灵活性.array是静态空间,一旦配置了,就不能改变:要换个大(或小)一点的可以,但琐碎的事由客户端完成:首先配置一块新空间,然后将元素从旧址一一搬往新址,再把原来的空间释还给系统.而vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素.它对内存的合理利用和灵活运用有很大的帮助. vector实现关键技术:对大小的控制以及重新配置时的数据移动效率

C++ STL学习——vector

学过C++的人肯定会很熟悉STL标准模板库,STL其实就是封装了一系列的接口,供我们调用.很多函数或者算法的实现不需要我们从头开始写,大大提高我们的编程效率.这篇博客在简单介绍STL的情况下,会详细的来介绍vector的使用. STL共有六大组件: 一.容器(Container):是一种数据结构,如list,vector,deque,queue等,以模板类的方法提供,为了访问容器中的数据,可以使用由容器类提供的迭代器. 二.迭代器(Iterator):提供了访问容器中对象的方法. 三.算法(Al