#节点类
class LNode:
def __init__(self,elem,next_=None):
self.elem=elem
self.next=next_
#自定义异常,在链表为空时访问元素抛出
class LinkListUnderflow(ValueError):
pass
#单链表类
class LList:
def __init__(self):
self._head= None
#判断链表是否为空
def is_empty(self):
return self._head is None
#在表头插入数据
def prepend(self,elem):
self._head=LNode(elem,self._head)
#删除表头节点并返回这个节点里的数据
def pop(self):
if self._head is None:
raise LinkListUnderflow("in pop")
e=self._head.elem
self._head=self._head.next
return e
#在表尾插入数据
def append(self,elem):
if self._head is None:
self._head=LNode(elem)
return
p=self._head
while p.next is not None:
p=p.next
p.next=LNode(elem)
#删掉表中最后一个元素
def pop_last(self):
if self._head is None:
raise LinkListUnderflow("in pop_last")
p=self._head
if p.next is None:
e=p.elem
self._head=None
return e
while p.next.next is not None:
p=p.next
e=p.next.elem
p.next=None
return e
#打印链表
def printall(self):
p=self._head
while p is not None:
print(p.elem,end="")
if p.next is not None:
print("->",end="")
p=p.next
print()
#定义链表迭代器
def elements(self):
p=self._head
while p is not None:
yield p.elem
p=p.next
#筛选生成器,删选表中符合条件的元素
#pred为条件表达式
def fliter(self,pred):
p=self._head
while p is not None:
if pred(p.elem):
yield p.elem
p=p.next
测试部分
llsit=LList()
for i in range(10):
llsit.prepend(i)
llsit.printall()
结果:
9->8->7->6->5->4->3->2->1->0
h=llsit.pop()
print(h)
llsit.printall()
结果:
9
8->7->6->5->4->3->2->1->0
llsit.append(h)
llsit.printall()
结果:
8->7->6->5->4->3->2->1->0->9
last=llsit.pop_last()
print(last)
llsit.printall()
结果:
9
8->7->6->5->4->3->2->1->0
for i in llsit.elements():
print(i)
结果:
8
7
6
5
4
3
2
1
0
for x in llsit.fliter(lambda y:y%2==0):
print(x)
结果:
8
6
4
2
0
改进
以上单链表在删除最后一个元素时,必须从头部进行查找,直到找到最后一个元素,为了提高此类操作的效率,考虑对上述链表结构进行改进,改进后的结构如下图所示:
在链表对象中增加一个尾部节点的引用域, 有了这个域,只需常量时间就可以实现删除表的最后一个元素。
可以通过继承前面定义的LList类的方法实现改进的链表类。
class LList1(LList):
def __init__(self):
LList.__init__(self)
self._rear=None#链表尾部引用域
#重写头部插入元素方法
def prepend(self,elem):
if self._head is None: #是空表
self._head=LNode(elem,self._head)
self._rear=self._head
else:
self._head = LNode(elem, self._head)
#重写尾部插入元素方法
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
#重写尾部删除元素方法
def pop_last(self):
if self._head is None: #是空表
raise LinkListUnderflow("in pop_last")
p = self._head
if p.next is None: #表中只有一个元素
e = p.elem
self._head = None
return e
while p.next.next is not None:
p = p.next
e = p.next.elem
p.next = None
self._rear=p
return e
循环链表
循环链表的尾节点指向它的头结点,形成一个环。
前端插入相当于在尾节点后插入,后端插入相当于在尾节点后插入然后将尾节点后移。
#循环链表类
class LCList:
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: #是空表
raise LinkListUnderflow("in pop")
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