秩的位置
可否模仿向量的循秩访问发方式?
- 可以,比如通过重载下标运算符
template <typename T> //assert: 0 <= r <= size
T List<T>::operator[](Rank r) const {
Post(T) p = first();
while (0<r--) p = p->succ;
return p->data;
}
但是这种用法的效率十分低下
假设这种链表的长度为n,算法的复杂的为o(n),既线性的时间
查找
在当前的列表L中,对于一个特定的元素p,查找位于p前n个元素中是否有所求元素e
在节点p(可能是trailer)的n和(真)前驱中,找到等于e的最后者
template <typename T> //从外部调用时,0 <= n <= ranl(p) < size
Posi(T) List<T>::find(T const & e, int n, Post(T) p) const {
while(0 < n--) //从右向左逐个比较
if(e == (p = p->pred)->data)
return p; //直至命中或范围越界
return NULL; //查找失败
}
函数对外的接口形式为 find(e, n, p),可以按形式提示为查找p前n个元素
相对的,若将函数定义为 find(e, p, n) ,可理解为查找p后的n个元素
插入与复制
插入
对于链表的插入操作,将新建节点e插入到特点节点p前为例
定义插入函数
template <typename T> List<t>::insertBefore(Posi(T) p, T const& e)
{
_size++;
return p->insertAsPred(e); //将e当作p的前驱插入
}
template <typename T> //前插入算法
Posi(T) ListNode<T>::insertAsPred(T const& e) {
Posi(T) s = new ListNode(e, pred, this);
pred->succ = s;
pred = s;
return s;
}
注意,当p为首节点时,插入仍可以成功完成
我们在定义列表(链表)时,定义了两个“哨兵”,header和trailer
复制
基于复制的构造函数如下
template <typename T>
void List<T>::copyNodes(Posi(T) p, int n) {
init(); //初始化链表
while(n--)
{
insertAsLast(p->data);
p=p->succ;
}
}
整体的代码思想很好理解,就是简单的从后遍历长度为n的链表,而代码中的insertAsLast不用像上文的insertAsFirst一样重新定义。
同样想到链表的定义,由于我们每次都会像新的链表的最后一个位置插入元素,也就是Last元素,而实际上链表存在着一个Trailer哨兵,始终代表着链表的结尾
那么insert AsLast实际上就是insertBefore(trailer-)