单链表的实现有一个缺点:尾端加入元素的效率很低,需要从头开始查找,直至找到最后一个节点才能进行插入操作。一种改进这种问题的方法是:在表中增加一个表尾节点引用域,有了这个域,就可以实现O(1)的尾端元素插入。具体如图1所示。
1 通过继承和派生来实现单链表的变形
基类为LList类,带有尾节点域的类继承自LList,同时我们需要对一些函数进行修改,具体如下:
class LList1(LList):
#define class methods and others
def __init__(self):
LList.__init__(self)
self._rear=None
# insert the Node from the head of the List
def prepend(self,elem):
'''
self._head=LNode(elem,self._head)
if self._rear is None:
self._head=self._rear
'''
if self._head is None:
self._head=LNode(elem,self_head)
self._rear=self._head
else:
self._head=LNode(elem,self._head)
#insert the Node from the tail of the List
def append(self,elem):
if self._head is None:
self._head=LNode(elem,self_head)
self._rear=self._head
else
self._rear.next=LNode(elem)
self._rear=self._rear.next
#pop the last elem from the list
def pop_last(self):
if self._head is None:
raise LinkedListUnderFlow("in pop_last")
p=self._head
if p.next is None:
e=p.elem
self._head=None
return e
while p.next is not None:
p=p.next
e=p.next.elem
p.next=None
self._rear=p
return e
下面是一段使用这个类的代码
mlist1=LList1()
mlist1.prepend(99)
for i in range(11,20):
mlist1.append(randint(1,20))
for x in mlist1.filter(lambda y:y % 2 == 0):
print x
2 循环单链表
单链表的另一种变形是循环单链表,其中最后一个节点的next域不用为None,而是指向表的第一个结点。如下图所示,仔细考虑之后就会发现,在链表对象里记录表尾节点更为合适,这样可以同时支持O(1)时间的表头/表尾插入和O(1)时间的表头删除。
现在考虑一个循环单链表类,只讨论几个典型操作,循环单链表与单链表的差异在于扫描循环的结束控制。
这种表只需要一个数据域_rear,它在逻辑上始终引用着表的尾节点。前端加入结点,就是在尾节点和首节点之间加入新的首节点,尾节点引用保持不变。通过尾节点引用很容易实现这一步;另一方面,尾端加入结点也是在原尾节点之后(与首节点之间)插入新节点,只是插入后要把它作为新的尾结点,因此需要更新表尾结点的引用。这两个操作需要考虑空表的插入情况。对于元素的输出,关键在于循环结束的控制。
循环单链表类
from LNode import LNode
import sys
class LCList(object):
def __init__(self):
self._rear=None
def is_empty(self):
return self._rear is None
def prepend(self,elem):
p=LNode(elem)
if self._rear is None:
p.next=p
self._rear=p
else:
p.next=self._rear.next
self._rear.next=p
def append(self,elem):
self.prepend(elem)
self._rear=self._rear.next
def pop(self):
if self._rear is None:
sys.exit(1)
p=self._rear.next
if self._rear is p:
self._rear=None
else:
self._rear.next=p.next
return p.elem
def printall(self):
if self.is_empty():
return
p=self._rear.next
while True:
print p.elem,"-> "
if p is self._rear:
break
p=p.next
if __name__=="__main__":
PLC=LCList()
PLC.prepend(90)
for i in range(11,30):
PLC.append(i)
PLC.printall()
参考文献
裘宗燕 . 数据结构与算法:Python语言描述[M]. 北京:机械工业出版社,2016:89-92.