昨天向量那章没看完,今天继续看
常规向量
书中实现了一个向量类的基本接口的方法,在此记录一下
置乱方法
template<typname T> void permute(Vector<T>& v)
{
for(int i = v.size; i > 0; i--)
{
swap(v[i-1], v[rand() % i]);
//置换第i-1个元素与下标范围在[0, i)间的任意一个元素
}
}
置乱某个区间的向量
template<typename T> void Vector<T>::permute(Rank lo, Rank hi)
{
T* v = _elem + lo;
//将子向量_elem[lo, hi]视为新向量v[0, hi - lo]
for(Rank i = hi - lo; i > 0; i--)
{
swap(v[i], v[rand() % i]);
}
}
时间复杂度为O(n)。
无序向量:支持比对(判等),未必支持比较(大小)的向量。
顺序查找:逐个比对查找的方式。最好情况为O(1),最坏情况为O(n)。
template<typename T> Rank Vector<T>::find(const* e, Rank lo, Rank hi)
{
while((lo < hi --) && (e != _elem[hi])){ }
return hi;
}
插入:在位置r插入元素e:将n到r元素依次后移,将元素e赋值到位置r上。
template<typname T> void Vector<T>::insert(Rank r, const& e)
{
expand(); //如果有必要需要扩展数组
for(int i = size; i > 0; i--)
{
_elem[i] = _elem[i - 1];
}
_elem[r] = e;
size++;
}
删除:删除从lo到hi的元素:依次将从hi到n的元素赋值给从lo开始的地址。
template<typename T> void Vector<T>::remove(Rank lo, Rank hi)
{
if(hi > size) reuturn;
whil(hi < size)
{
_elem[lo++] = _elem[hi++];
}
size = size - hi + lo;
shrink(); //如果有必要需要缩小数组空间
}
去重:每次在范围[0, i)内查找是否包含元素v[i],如果不包含则 i++,如果包含则删除v[i]。由于同时包含了查找和删除,二者的时间复杂度分别为O(n),所以去重的总时间复杂度为O(n(2))。
有序向量
所有元素按照线性次序存放,并且这些元素的数值也按照此次序单调分布,称为有序向量。
由于不要求元素互异,通常约定非降序序列为
对于任意 0<= i < j < n 都有 V[i] <= V[j]。
由于有序向量的特性,针对于有序向量的去重,如果还是用和无序向量中相同的去重方法则效率太低,所以有序向量中的去重利用有序向量的特性,设置两个动态下标同时进行比较和替换,当两个值不同时,将后一个值移到前一个值之后,最后直接截掉遍历结束后尾部多余的元素。
template<typename T> void Vector<T>::uniquify()
{
Rank i = 0;
Rank j = 0;
while(++j < size)
{
if(_elem[i] != _elem[j])
{
_elem[i++] = _elem[j];
}
}
size = i++;
shrink();
}
列表
元素也构成线性逻辑次序,但是元素的物理地址可以任意。“循位置访问”/“循链接访问”。
链表:典型动态存储结构。其中的数据分散为一系列节点,节点和节点之间通过指针相互索引和访问。
默认构造方法,需运行常数时间
template<typename T> void List<T>::init()
{
header = new ListNode<T>;
trailer = new ListNode<T>;
header -> succ = trailer;
header -> pred = null;
trailer -> succ = null;
trailer -> pred = header;
size = 0;
}
查找,时间复杂度为O(n)
template<typename T> ListNodePosi<T> List<T>::find(T const& e, int n, ListNodePosi<T> p)
{
while(n-- > 0)
{
if(e == (p = p -> pred) -> data)
{
return p;
}
}
return null;
}
前插入(在当前节点this前插入)
template<typename T> ListNodePosi<T> List<T>::InsertAsPred(T const& e)
{
ListNodePosi(T) x = new List(e, pred, this);
pred -> succ = x; //前结点的后继为x
pred = x; //当前结点的前驱为x
return x;
}
后插入
template<typename T> ListNodePosi<T> List<T>::InsertAsSucc(T const& e)
{
ListNodePosi(T) x = new List(e, this, succ);
succ -> pred = x;
succ = x;
return x;
}
二者的时间复杂度均为常数