内部数组所占的物理空间的容量,若在向量的生命期内不允许调整,则称作静态空间管理策略。
向量的实际规模与其内部的数组容量的比值(_size/_capacity),亦称作装填因子(他是衡量空间利用率的重要指标)
所以如何才能保证向量的装填因子既不至于超过1,也不至于太接近0,这时候需要动态空间管理了。
template<typename T> void vector<T> : : expend(){ //向量空间不足是扩容
if(_size<_capacity) return ;//容量够用时不扩容
if(_capacity<DEFAULT_CAPACITY) _capacity=DEFAULT_CAPACITY;//不低于最小容量
T*oldElem=_elem; _elem= new T[_capacity<<=1];//容量加倍
for(int i=0;i<_size;i++)
_elem[i]=oldElem[i];//复制原向量内容(T为基本类型,或已重载赋值操作符'=')
delete[] oldElem;//释放空间
}
按照上述程序,每进行一次扩容,其容量都会加倍。但需要至少进行n次插入操作,才会因为可能溢出而再次扩容。随着向量规模的不断扩大,在执行插入操作之前需要进行扩容的概率,也将迅速降低。所以就某种平均意义而言,用于扩容的时间成本不至于很高。这里就引入了分摊复杂度进行说明。
将程序所消耗的时间,分摊至所有的操作。这样分摊平均至单次操作的时间成本,称为分摊运行时间。
因为在足够长的连续操作序列中,以任何固定间隔连续出现上述最坏情况的概率为0,故常规的平均复杂度不具有参考意义。
size(n) = 连续插入n个元素后向量的规模
capacity(n)=连续插入n个元素后数组的容量
T(n)=为连续插入n个元素而花费于扩容的时间
size(n)<=capacity(n)<2*size(n)
capacity(n)=
容量以2为比例按指数速度增长,在容量达到capacity(n)之前,共做过次
所有T(n)=2N+4N+8N+......+capacity(n)<2*capacity(n)=
将其分摊到其间的连续n次操作,单次操作所需的分摊运行时间应为
另一个导致低效率的情况是,向量的实际规模可能远远小于内部数组的容量。比如在连续的一系列操作过程中,若删除操作远多于插入操作,则装填因子可能远远小于100%,甚至非常接近与0.当装填因子低于某一阈值时,我们称数组发生了下溢。
这时候就要用缩容
template<typename T> void vector<T>::shrink(){
if(_capacity<DEFAULT_CAPACITY<<1) return ;//不致收缩到DEFAULT_CAPACITY以下
if(_size<<2>_capacity) return ;//以25%为界
T*_oldelem=_elem ;
_elem=new T[_capacity>>=1];//容量减半
for(int i=0;i<_size;i++) _elem[i]=_oldelem[i];
delete[] oldelem;
}