def__eq__(self, other): """检查二者是否具有相同的位置信息 重载运算符 ==""" returntype(other) istype(self) and other._node isself._node
def__ne__(self, other): """与上面相反 重载运算符 !=""" returnnotself == other
# -------------- 检查位置类、为节点实例化位置类 -------------- def_validate(self, p): """检查是否是合法的 Position 类,返回位置类存储的节点类""" ifnotisinstance(p, self.Position): raise TypeError('p must be proper Position') if p._container isnotself: # 检查当前位置类 p 是否属于当前列表,以免误操作了别的列表 raise ValueError('p does not belong to this container') if p._node._nextisNone: raise ValueError('p is no longer valid') return p._node
def_make_position(self, node): """对每个节点,实例化它的位置类""" if node isself._header or node isself._trailer: returnNone else: # 创建属于当前列表的位置类 returnself.Position(self, node)
defadd_before(self, p, e): """在位置类 p 前插入""" original = self._validate(p) returnself._insert_between(e, original._prev, original)
defadd_after(self, p, e): original = self._validate(p) returnself._insert_between(e, original, original._next)
defdelete(self, p): """删除位置类 p 返回 p 上的值""" original = self._validate(p) returnself._delete_node(original) # 父类方法
defreplace(self, p, e): """替换位置 p 的值为 e,返回 p 位置之前的值""" original = self._validate(p) old_value = original._element original._element = e return old_value
1.2.1 定义 Position 类
定义位置类 Position 用来方便的得到每个节点的位置。因为只要位置信息已知,链表的插入和删除操作的复杂度为 O(1) 。
假设对于一个空的收藏夹列表,我们访问 n 个网页 1, 2, 3, ..., n 分别连续 n 次。因为按照访问次数排序,则对于第一个网页,每次访问需要 O(1) ,对于第二个网页每次都要和前一个网页比较(并且在访问 n 次之前都不会排在前一个元素前面),每次访问需要 O(2) ,以此类推,每个访问 n 次:
n+2n+3n+⋯+n⋅n=n⋅2n(n+1)∼O(n3)
时间复杂度为 O(n3) ,这是极其低效的。
但是采用 More-To-Front 算法,即按照访问时间排序,最后被访问的网页排在第一。如此对于任何一个网页,连续访问 n 次都是 O(1) ,因为访问第一次后,这个网页就位于第一个位置,链表查询第一个位置只需要 1 次操作。于是,每个访问 n 次的总时间:
# -------------- 只需要重载/覆写 _move_up() 和 top() 方法即可 -------------- def_move_up(self, p): """每次调用意味着被访问,被访问就移到最前""" if p != self._data.first(): self._data.add_first(self._data.delete(p))
deftop(self, k): """因为列表无序,需要找到最大的前 k 个元素""" ifnot1 <= k <= len(self): raise ValueError('Illegal value of k')
# 临时复制一份原列表 temp = PositionalList() for item inself._data: temp.add_last(item)
for j inrange(k): # 遍历一边找到最大的 highPos = temp.first() walk = temp.after(highPos) while walk isnotNone: if walk.element()._count >= highPos.element()._count: highPos = walk walk = temp.after(walk) yield highPos.element()._value