2.4 插入、删除、唯一化和遍历

插入,不赘述,代码如下:
 
template <typename T>
Rank Vector<T>::insert(Rank r,T const& e) {
       expand();
       for (int i = _size; i > r; i--)
               _elem[i] = elem[i-1];//复制原向量内容
       _elem[r] = e;
       _size++;
       return r;
}
 
插入前,要使用expand()算法核实是否即将溢出,然后为了保证数组元素物理地址的连续性,将后缀_elem[r,_size)整体后移一个单位,这一步也是时间的主要消耗来源。后缀长度与所费时间是成线性正比的关系。一般地,若插入位置等概率分布,则平均运行时间为O(_size)=O(n)。
 
删除操作有两个接口:1.remove(r),即删除秩为r的单个元素;2.remove[lo,hi),删除区间为[lo,hi)的元素。所以我们免不了的要有这两个思考角度。删除一定区间范围的元素,是直接使用第二个接口呢?还是说对第一钟删除的接口操作进行重复调用从而达到异曲同工的目的。实际上,第二种做法是不可取的。因为数组中的元素地址是必须连续的,故而每次删除一个元素,都需要将所有后继元素向前移动一个单元,若后继元素共有m=_size-hi个,则对remove(r)的每次调用都需要移动m次;对于整个区间,移动的次数将会累计达到m*(hi-lo)个,既是后缀长度和待删除区间宽度的乘积。
 
那么,我们能否通过删除区间元素的接口来删除单个元素呢?即将删除单个元素作为删除整个区间元素的特例。答案是肯定的。这样做可以将移动操作的次数控制在O(m)以内。
 
区间删除即remoove[lo,hi)以及单元素删除即remove(r)的代码如下:
 
template <typename T> int Vector<T>::remove(Rank lo,Rank hi) {
       if (lo == hi)
               return 0;
       while (hi <= _size)
               _elem[lo++] = _elem[hi++];
       _size = lo;
       shrink();
       return hi - lo;
}
 
template <typename T> T Vector<T>::remove(Rank r) {
       T e = _elem[r];
      remove(r,r + 1);
       return e;
}
 
唯一化,使唯一,剔除重复元素。首先介绍无序向量的唯一化代码:
 
template <typename T> int Vector<T>::deduplicate() {
       int oldSize = _size;
       Rank i = 1;
       while (i < _size)
               (find(_elem[i], 0, i) < 0) ? i++ : remove(i);
       return oldsize - _size;
}
 
简单易懂,故而跳过讲解。
 
无序向量的唯一化复杂度具有明显的单调性:随着循环的不断进行,当前元素的后继持续地严格减少。也就是说,经过n-2步迭代之后该算法必然终止。而该算法所主要消耗的时间在于find()和remove()两个接口。总体复杂度为O(n*n)。
 
遍历
 
遍历即使将向量作为一个整体,对其中所有元素实施某种统一的操作,比如输出向量中的所有元素,或者按照某种运算流程统一修改所有元素的数值。代码入下:
 
template <typename T> void Vector<T>::traverse(void (*visit)(T&)) {//借助函数指针机制遍历向量
       for (int i = 0; i < _size; i++)
               visit(_elem[i];)
}
template <typename T> template <typename VST>//元素类型、操作器
void Vector<T>::traverse(VST& visit) {//借助函数对象机制,遍历向量
       for (int i = 0; i < _size; i++)
               visit(_elem[i]);
}
 
前一种方法借助函数指针*visit()指定某一函数。该函数只有一个参数。其类型为对向量元素的引用。可以通过该函数即可直接访问或修改向量元素。
 
后一种方法借助函数对象的形式,指定具体的遍历操作。这类对象的操作符“()”经重载后,在形式上等效于一个函数接口。这种方式功能更强,使用范围更广。

猜你喜欢

转载自www.cnblogs.com/NK-007/p/9195789.html