3.9插入
template<typename T>
Rank vector<T>::insert(T const & e, Rank r)
{
expand();//检查是否需要扩容。
for (Rank i = _size; i > r; i--)//自后向前,所有元素顺次后移一个单元
_elem[i] = _elem[i - 1];
_elem[r] = e; _size++;
return r;
}
注意:元素搬迁的顺序不能颠倒,否则会因元素被覆盖而造成数据丢失。向量结构的插入较之列表结构,复杂度就集中在元素搬迁上,线性正比于后缀的长度。考虑最坏情况,依次从首部插入,元素移动个数成几何级数由N递减至1。故总体时间复杂度为O(N+N-1+N-2+….+1)=O(n^2)。
4.0删除
由于向量元素的特性,考察{1,2,3,4,5}一组向量。删除元素3,需要将4,5顺次前移一个单元{1,2,4,5,NULL},与插入元素同理,每次单个删除一个元素,需要时间线性正比其后继元素。若区间删除(2(rank),4(rank))变为{1,2,NULL,NULL,NULL}而所费时间与删除单个元素3完全相同。故应采用区间删除的办法来取代单个元素。
template<typename T>
int vector<T>::remove(Rank lo, Rank hi)
{//lo与hi必须合法[0,_size)
if (lo == hi) return 0;
while (hi < _size) {
_elem[lo++] = _elem[hi++];
}
_size = lo;
shrink();//装填因子25%为界,低于25%将缩容
return hi-lo;
}
重载remove()接口以实现单元素删除。
template<typename T>
T vector<T>::remove(Rank r)
{
if(IsValid(r,0,_size)){
T e = _elem[r];
remove(r, r + 1);
return e;
}
else return NULL;
}
4.1唯一化
对于无序向量来说,唯一化的办法只有遍历一遍向量O(n),剔除重复的,删除元素需要反复调用remove()接口。也需要O(n)时间。即总体时间复杂度为O(n^2)的时间。
template<typename T>
int vector<T>::deduplicate()
{
Rank i = 1;
int oldsize = _size;
while (i < _size) {
(find(_elem[i], 0, i) < 0) ? i++ : remove(i);//自前向后,与其所有前驱比较,找到一个删除一个。
}
return oldsize-_size;
}
针对有序向量,唯一化的工作即可在O(n)时间内完成。无序向量唯一化,时间复杂度主要集中在每次调用remove()接口上,每次只移动一个单元,如果能标记位置,一次前移多个单元,时间复杂度将大大下降。
以{1,3,5,5,5,5,5,5,6}为例。
采用deduplicate()接口,当指针处理到rank(3)时{1,3,5,5},find(_elem[3], 0,3)=2这时调用一次remove()接口,在接下来的4次比对中,需要连续调用4次remove()接口,这将大大提升复杂度。若能直接调用remove(2,7)即可在O(9+5)时间结束任务。
在处理当前问题是,发现重复元素必然是紧邻出现的。采取如下思路:
template<typename T>
int vector<T>::uniquify()
{
Rank i = 0, j = 0;
while (++j < _size) {
if (_elem[i] != _elem[j])
_elem[++i] = _elem[j];
_size = ++i; shrink();
}
return j - i;
}
i与j分别指向下一对相邻子区间的首元素每次将检查一对儿数据元素,故可在O(n)时间内完成任务。