今天,我们来模拟实现vector。
首先,我们来讲一下vector的特性:
1:能够存放各种类型的动态增容的顺序容器
2:支持随机访问。
也就是说,他的对象创建之后,当插入一个数据时,可以自己动态的开辟空间,不需要程序员手动的开辟。并且这个数据可以是任意类型的。因为vector实现了operator[]这个接口,使得他支持随机访问。
vector有三个主要的成员变量,分别是:
start:数据起始位置。
finish:所存放的最后一个元素的下一个位置。
endofstarge:所开辟的空间的最后一个位置的下一个位置。
如下图所示:
红色部分为已存储的空间。最后四格为开辟好的空间,但是还没有存储的数据的空间。
vector的优点与缺点:
优点:
(1)支持随机访问,即[]和at()。
(2)节省空间。相比较链表而言(链表每个节点不仅要存储内部值的大小还是要存储指向下个节点和上个节点的指针)
(3)可以像数组一样的操作。
缺点:
(1)在内部进行增删效率较低。
(2)只能在vector的最后进行push和pop操作。不能再开头进行push和pop操作。
(3)当capacity满时,再插入数据,数据的开辟,拷贝,释放代价大。
接下来,再说说vector的模拟实现的接口。
(1)push_back
//在这里,_start,_finish,_endofstarge分别对应着上面所述的start,finish,endofstarge.
void CheckCapacity()//检查是否需要扩容。
{
size_t Size = _size();//存储的元素的数量
size_t Capacity = _capacity();//开辟空间的大小
if (_finish == _endofstarge)//该条件成立说明开辟的空间已经被全部存上了数据
{
//Capacity > 0 ? Capacity * 2 : 3;
if (Capacity)
{
Capacity = Capacity * 2;
}
else
{
Capacity = 3;
}
T* _tmp = new T[Capacity];//开辟新的空间
for (size_t i = 0; i < _size(); i++)
{
_tmp[i] = _start[i];//将旧的空间的全部数据拷贝至新的空间
}
delete[] _start;//释放旧空间
_start = _tmp;
_finish = _tmp + Size;
_endofstarge = _tmp + Capacity;
}
}
void Push_back(const T& x)
{
CheckCapacity();
*_finish = x;//push进新数据。
_finish++;
}
(2)在某一个位置插入一个值
void Insert(Iterator pos, const T& x)
{
CheckCapacity();//检查是否需要扩容
Iterator it1 = Begin();
if (pos != it1)如果所要找到的位置是否是头为两种考虑方式。
{
while (it1 != End())//轮询依次找到所要找的位置。
{
if (it1 == pos)
{
break;
}
++it1;
}
}
//这里插入的方法是找到对应的位置后,将该位置及其以后的元素全部后移一位。
Iterator it2 = End();
while (it2 != it1)
{
--it2;
T a = *it2;
Iterator it = it2;
*(++it) = a;
}
*it2 = x;//插入新元素
++_finish;
}
(3)删除一个某一个值为x元素
//当找到这个元素时,需要将这个元素后面的所有元素全部前移一个位置。
//并且删除的是当前这个数组里所有出现的这个值。
void Earse(const T& x)
{
Iterator it1 = Begin();
while (it1 != End())
{
if (*it1 == x)
{
Iterator it = it1;
++it;
while (it != End())
{
T a = *it;
*(it - 1) = a;
++it;
}
if(it1 != Begin())
--it1;
_finish--;
}
++it1;
}
}
谢谢大家。